From 5830befcea86c1d8db2fd864c8f6963e84c2991e Mon Sep 17 00:00:00 2001 From: robertl Date: Thu, 20 Apr 2006 02:20:18 +0000 Subject: [PATCH] Largescale overhaul of the JEEPs interface to: * Vastly widen device support * Provide better independence of serial/usb. * Provice better separation of USB protocol and physical layer. * Provice better independence of the various OS layers. --- gpsbabel/jeeps/garminusb.h | 7 +- gpsbabel/jeeps/gps.h | 17 +- gpsbabel/jeeps/gpsapp.c | 635 ++++++++++++++++++++------------- gpsbabel/jeeps/gpsapp.h | 9 +- gpsbabel/jeeps/gpscom.c | 45 ++- gpsbabel/jeeps/gpscom.h | 6 +- gpsbabel/jeeps/gpsdevice.c | 86 +++++ gpsbabel/jeeps/gpsdevice.h | 73 ++++ gpsbabel/jeeps/gpsdevice_ser.c | 37 ++ gpsbabel/jeeps/gpsdevice_usb.c | 59 +++ gpsbabel/jeeps/gpslibusb.c | 210 +++++------ gpsbabel/jeeps/gpsmem.c | 3 +- gpsbabel/jeeps/gpsprot.c | 3 +- gpsbabel/jeeps/gpsprot.h | 15 + gpsbabel/jeeps/gpsread.c | 31 +- gpsbabel/jeeps/gpsread.h | 8 +- gpsbabel/jeeps/gpsrqst.c | 13 +- gpsbabel/jeeps/gpsrqst.h | 4 +- gpsbabel/jeeps/gpssend.c | 21 +- gpsbabel/jeeps/gpssend.h | 7 +- gpsbabel/jeeps/gpsserial.c | 240 ++++++------- gpsbabel/jeeps/gpsserial.h | 30 +- gpsbabel/jeeps/gpsusbcommon.c | 114 ++++-- gpsbabel/jeeps/gpsusbint.h | 6 +- gpsbabel/jeeps/gpsusbread.c | 45 +-- gpsbabel/jeeps/gpsusbsend.c | 4 +- gpsbabel/jeeps/gpsusbstub.c | 6 +- gpsbabel/jeeps/gpsusbwin.c | 319 +++++++---------- gpsbabel/jeeps/gpsutil.h | 1 + 29 files changed, 1229 insertions(+), 825 deletions(-) create mode 100644 gpsbabel/jeeps/gpsdevice.c create mode 100644 gpsbabel/jeeps/gpsdevice.h create mode 100644 gpsbabel/jeeps/gpsdevice_ser.c create mode 100644 gpsbabel/jeeps/gpsdevice_usb.c diff --git a/gpsbabel/jeeps/garminusb.h b/gpsbabel/jeeps/garminusb.h index 569c23749..a05f9c15d 100644 --- a/gpsbabel/jeeps/garminusb.h +++ b/gpsbabel/jeeps/garminusb.h @@ -1,7 +1,7 @@ /* Definitions for Garmin USB protocol and implementation. - Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + Copyright (C) 2004, 2005, 2006 Robert Lipe, robertlipe@usa.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -56,9 +56,8 @@ struct garmin_unit_info { int gusb_cmd_send(const garmin_usb_packet *obuf, size_t sz); int gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz); -int gusb_open(const char *portname); -int gusb_close(const char *portname); -int gusb_init(const char *portname); +int gusb_init(const char *portname, gpsdevh **dh); +int gusb_close(gpsdevh *); /* * New packet types in USB. diff --git a/gpsbabel/jeeps/gps.h b/gpsbabel/jeeps/gps.h index fa3af7ea0..3a0c66e86 100644 --- a/gpsbabel/jeeps/gps.h +++ b/gpsbabel/jeeps/gps.h @@ -86,9 +86,12 @@ typedef struct GPS_STrack time_t Time; /* Unix time */ float alt; /* Altitude */ float dpth; /* Depth */ + float temperature; /* Temperature. Degrees Celsius. */ + int temperature_populated; /* True if above is valid. */ int32 heartrate; /* Heatrate as in Garmin 301 */ - int32 tnew; /* New track? */ - int32 ishdr; /* Track header? */ + unsigned int tnew:1; /* New track? */ + unsigned int ishdr:1; /* Track header? */ + unsigned int no_latlon:1; /* True if no valid lat/lon found. */ int32 dspl; /* Display on map? */ int32 colour; /* Colour */ char trk_ident[256]; /* Track identifier */ @@ -152,8 +155,12 @@ typedef struct GPS_SWay char rte_link_subclass[18]; char rte_link_ident[256]; - char Time_populated; /* 1 if true */ - time_t Time; /* Unix time */ + char time_populated; /* 1 if true */ + time_t time; /* Unix time */ + char temperature_populated; + float temperature; /* Degrees celsius. */ + uint16 category; + } GPS_OWay, *GPS_PWay; /* @@ -173,7 +180,7 @@ typedef struct GPS_SLap_Data { -#include "gpsserial.h" +#include "gpsdevice.h" #include "gpssend.h" #include "gpsread.h" #include "gpsutil.h" diff --git a/gpsbabel/jeeps/gpsapp.c b/gpsbabel/jeeps/gpsapp.c index b815edcae..967c95b83 100644 --- a/gpsbabel/jeeps/gpsapp.c +++ b/gpsbabel/jeeps/gpsapp.c @@ -4,7 +4,7 @@ ** @author Copyright (C) 1999 Alan Bleasby ** @version 1.0 ** @modified Dec 28 1999 Alan Bleasby. First version -** @modified 2004, 2005, 2006 Robert Lipe +** @modified Copyright (C) 2004, 2005, 2006 Robert Lipe ** @@ ** ** This library is free software; you can redistribute it and/or @@ -23,13 +23,19 @@ ** Boston, MA 02111-1307, USA. ********************************************************************/ #include "gps.h" -#include "garminusb.h" #include #include #include #include #include +/* + * This violates the layering design, but is needed for device discovery. + * See the use of gps_is_usb and GPS_Packet_Read_usb below. + */ +#include "garminusb.h" +#include "gpsusbint.h" + #define XMIN(a,b) (a < b? a : b) static int32 GPS_A000(const char *port); @@ -74,6 +80,8 @@ static void GPS_D152_Send(UC *data, GPS_PWay way, int32 *len); static void GPS_D154_Send(UC *data, GPS_PWay way, int32 *len); static void GPS_D155_Send(UC *data, GPS_PWay way, int32 *len); +static void GPS_D120_Get(int n, char *data); + static void GPS_D200_Get(GPS_PWay *way, UC *s); static void GPS_D201_Get(GPS_PWay *way, UC *s); static void GPS_D202_Get(GPS_PWay *way, UC *s); @@ -90,10 +98,10 @@ static void GPS_D400_Send(UC *data, GPS_PWay way, int32 *len); static void GPS_D403_Send(UC *data, GPS_PWay way, int32 *len); static void GPS_D450_Send(UC *data, GPS_PWay way, int32 *len); -static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, int32 fd); -static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, int32 fd); -static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, int32 fd); -static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, int32 fd); +static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd); +static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd); +static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd); +static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd); static void GPS_D500_Send(UC *data, GPS_PAlmanac alm); static void GPS_D501_Send(UC *data, GPS_PAlmanac alm); static void GPS_D550_Send(UC *data, GPS_PAlmanac alm); @@ -148,17 +156,16 @@ int32 GPS_Init(const char *port) (void) GPS_Util_Little(); - /* - * Decide here if the portname refers to a USB device and set the - * global that's used as in inflection point for other decisions later. - */ - gps_is_usb = (0 == strncmp(port, "usb:", 4)); - ret = GPS_A000(port); if(ret<0) return ret; - gps_save_time = GPS_Command_Get_Time(port); - if(!gps_save_time) { + + /* + * Some units may be unable to return time, such as a C320 when in + * charging mode. Only consider it fatal if the unit returns an error, + * not just absence of returning a time. + */ + if(gps_save_time < 0) { return FRAMING_ERROR; } @@ -180,16 +187,16 @@ int32 GPS_Init(const char *port) ************************************************************************/ static int32 GPS_A000(const char *port) { - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int16 version; int16 id; - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; - if(!gps_is_usb && !GPS_Serial_Flush(fd)) + if(!GPS_Device_Flush(fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -215,11 +222,17 @@ static int32 GPS_A000(const char *port) GPS_User("Unit:\t%s\nID:\t%d\nVersion:\t%.2f", gps_save_string, gps_save_id, gps_save_version); - +#if 0 gps_date_time_transfer = pA600; gps_date_time_type = pD600; /* All models so far */ gps_position_transfer = pA700; gps_position_type = pD700; /* All models so far */ +#else + gps_date_time_transfer = -1; + gps_date_time_type = -1; + gps_position_transfer = -1; + gps_position_type = -1; +#endif gps_pvt_transfer = -1; gps_pvt_type = -1; gps_prx_waypt_transfer = -1; @@ -229,7 +242,7 @@ static int32 GPS_A000(const char *port) gps_trk_hdr_type = -1; gps_rte_link_type = -1; - if(!GPS_Serial_Wait(fd)) + if(!GPS_Device_Wait(fd)) { GPS_Warning("A001 protocol not supported"); id = GPS_Protocol_Version_Change(id,version); @@ -246,28 +259,47 @@ static int32 GPS_A000(const char *port) * reading until we incur a timeout. * Worse still, the serial layer assumes a read timeout is a * fatal error, while the USB layer (correctly) returns that error - * to the caller. So we call GPS_Serial_Wait which spins into + * to the caller. So we call GPS_Device_Wait which spins into * a delay/select for the serial system and a NOP for USB. + * + * Worse _yet_, this is the one place in all of Garmin Protocolsville + * where we don't know a priori how many packets will be sent in + * response. Since we want the lower levels of the USB handler + * to handle the ugliness of the "return to interrupt" packets, we + * reach behind that automation here and hand that ourselves. */ for (i = 0; i < 25; i++) { rec->type = 0; - - if(!GPS_Serial_Wait(fd)) - goto carry_on; - if (GPS_Packet_Read(fd, &rec) <= 0) { - goto carry_on; - } + if (gps_is_usb) { + GPS_Packet_Read_usb(fd, &rec, 0); + } else { + if(!GPS_Device_Wait(fd)) + goto carry_on; - GPS_Send_Ack(fd, &tra, &rec); + if (GPS_Packet_Read(fd, &rec) <= 0) { + goto carry_on; + } + + GPS_Send_Ack(fd, &tra, &rec); + } if (rec->type == 0xfd) { - GPS_A001(rec); -/* XXX This is wrong. Since we don't have a timeout on a read in Windows - * (!) and this phase of the protocol is one of the very rare ones where we - * don't know how many packets to expect, we have a big problem here. - */ -goto carry_on; + GPS_A001(rec); + goto carry_on; + } + + /* + * If a 296 has previously been interrupted, it's going to + * ignore the session request (grrrr) and continue to send + * us left over packets. So if we see anything that isn't + * part of our A000 discovery cycle, reset the counter and + * continue to loop. + * + * Garmin acknowledges this is a firmware defect. + */ + if (rec->type < 0xf8) { + i = 0; } } fatal("Failed to find a product inquiry response.\n"); @@ -278,11 +310,10 @@ carry_on: if(gps_pvt_transfer != -1) GPS_A800_Off(port,&fd); - GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -343,113 +374,50 @@ static void GPS_A001(GPS_PPacket packet) case 'A': GPS_User("\nCapability %c%d:", tag, data); lasta = data; - if(data<100) - { - if(data==10) + switch (data) { + case 10: gps_device_command = pA010-10; - else if(data==11) - gps_device_command = pA011-10; - else - GPS_Protocol_Error(tag,data); - continue; - } - else if(data<200) - { - if(data==100) + break; + case 11: + gps_device_command = pA010-10; + break; + case 100: gps_waypt_transfer = pA100; - /* Ignore A101 Waypoint Category Transfer Protocol. */ - continue; - } - else if(data<300) - { - if(data==200) + break; + case 101: + gps_category_transfer = pA101; + break; + case 200: gps_route_transfer = pA200; - else if(data==201) + break; + case 201: gps_route_transfer = pA201; - else - GPS_Protocol_Error(tag,data); - continue; - } - else if(data<400) - { - switch (data) { - case 300: - gps_trk_transfer = pA300; - break; - case 301: - gps_trk_transfer = pA301; - break; - case 302: - gps_trk_transfer = pA302; - break; - default: - GPS_Protocol_Error(tag,data); - } - continue; - } - else if(data<500) - { - if(data!=400) - GPS_Protocol_Error(tag,data); - else + break; + case 300: + gps_trk_transfer = pA300; + break; + case 301: + gps_trk_transfer = pA301; + break; + case 302: + gps_trk_transfer = pA302; + break; + case 400: gps_prx_waypt_transfer = pA400; - continue; - } - else if(data<600) - { - if(data!=500) - GPS_Protocol_Error(tag,data); - else + break; + case 500: gps_almanac_transfer = pA500; - continue; - } - else if(data<700) - { - if (data == 600) + break; + case 600: gps_date_time_transfer = pA600; - else { - /* Stupid undocumented 60C packets */ - /* GPS_Protocol_Error(tag,data); */ - continue; - } - continue; - } - else if(data<800) - { - if(data!=700) - GPS_Protocol_Error(tag,data); - gps_position_transfer = pA700; - continue; - } - else if(data<900) - { - if (data == 800) + break; + case 700: + gps_position_transfer = pA700; + break; + case 800: gps_pvt_transfer = pA800; - /* - * Undocumented A802 packets introduced on Vista 3.60 f/w. - * else - * GPS_Protocol_Error(tag,data); - */ - continue; - } - else if (data < 1000) - { - /* Stupid Garmin undocumented "A900" packets - * as returned by GPS76, Emap, III, and V in - * later firmware. - */ - continue; - } - else if (data < 1100) - { - /* Stupid Garmin undocumented "A100[2345]" packets - * as returned by Forerunner 301. - */ - continue; - } - else - { - GPS_Protocol_Error(tag,data); + break; + } break; @@ -457,28 +425,50 @@ static void GPS_A001(GPS_PPacket packet) GPS_User(" %c%d", tag, data); if(lasta<200) { - if(data<=110 && data>=100) - { - gps_waypt_type = data; - continue; - } - if(data<153 && data>=150) - { - gps_waypt_type = data; - continue; - } - if(data<156 && data>=154) - { - gps_waypt_type = data; - continue; - } - if (data == 120) - { - /* Quest 3.0 has a D120 for Wpt category ignore it*/ - continue; + switch (data) { + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 110: + /* 15x is panel-mount aviation */ + case 150: + case 151: + case 152: + /* 153 not documented */ + case 154: + case 155: + gps_waypt_type = data; + break; + + /* + * Observered on Quest 3.0, 27xx, 27x, 29x. + */ + case 120: + gps_category_type = data; + break; + + case 200: + case 201: + case 202: + gps_rte_hdr_type = data; + break; + + /* 210 Link packets appear in newer models, but the + * doc isn't sufficiently clear on what they really + * mean. + */ + case 210: + gps_rte_link_type = data; + break; + } - else - GPS_Protocol_Error(tag,data); } @@ -531,6 +521,7 @@ static void GPS_A001(GPS_PPacket packet) case 301: gps_trk_type = pD301; break; case 302: gps_trk_type = pD302; break; case 303: gps_trk_type = pD303; break; + case 304: gps_trk_type = pD304; break; case 310: gps_trk_hdr_type = pD310; break; case 311: gps_trk_hdr_type = pD311; break; case 312: gps_trk_hdr_type = pD312; break; @@ -651,14 +642,14 @@ static void GPS_A001(GPS_PPacket packet) int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *)) { static UC data[2]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 n; int32 i; - if(!GPS_Serial_On(port,&fd)) + if(!GPS_Device_On(port,&fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -698,10 +689,13 @@ int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *)) if(!((*way)[i]=GPS_Way_New())) return MEMORY_ERROR; - if(!GPS_Packet_Read(fd, &rec)) + if(!GPS_Packet_Read(fd, &rec)) { return gps_errno; - if(!GPS_Send_Ack(fd, &tra, &rec)) + } + + if(!GPS_Send_Ack(fd, &tra, &rec)) { return gps_errno; + } switch(gps_waypt_type) { @@ -770,7 +764,7 @@ int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *)) if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) { - GPS_Error("A100_GET: Error transferring waypoints. Expected %d completion code. Got %d", LINK_ID[gps_link_type].Pid_Xfer_Cmplt, rec->type); + GPS_Error("A100_GET: Error transferring waypoints. Expected %d completion code. Got %d. %d of %d received", LINK_ID[gps_link_type].Pid_Xfer_Cmplt, rec->type, i, n); return FRAMING_ERROR; } @@ -783,7 +777,7 @@ int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *)) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return n; @@ -806,13 +800,13 @@ int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *)) int32 GPS_A100_Send(const char *port, GPS_PWay *way, int32 n, int (*cb)(GPS_PWay *)) { UC data[GPS_ARB_LEN]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 i; int32 len; - if(!GPS_Serial_On(port,&fd)) + if(!GPS_Device_On(port,&fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -919,13 +913,84 @@ int32 GPS_A100_Send(const char *port, GPS_PWay *way, int32 n, int (*cb)(GPS_PWay GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; } +/* + * Get the list of waypoint categories from the receiver. + */ +int32 GPS_A101_Get(const char *port) +{ + static UC data[2]; + gpsdevh *fd; + GPS_PPacket tra; + GPS_PPacket rec; + int32 n; + int32 i; + + + if(!GPS_Device_On(port,&fd)) + return gps_errno; + + if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) + return MEMORY_ERROR; + + GPS_Util_Put_Short(data, + COMMAND_ID[gps_device_command].Cmnd_Transfer_Wpt_Cats); + GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data, + data,2); + + if(!GPS_Write_Packet(fd,tra)) + { + GPS_Error("A101_Get: Cannot write packet"); + return FRAMING_ERROR; + } + + if(!GPS_Get_Ack(fd, &tra, &rec)) + { + GPS_Error("A101_Get: No acknowledge"); + return FRAMING_ERROR; + } + + GPS_Packet_Read(fd, &rec); + GPS_Send_Ack(fd, &tra, &rec); + + n = GPS_Util_Get_Short(rec->data); + for (i = 0; i < n; ++i) { + if(!GPS_Packet_Read(fd, &rec)) { + return gps_errno; + } + if(!GPS_Send_Ack(fd, &tra, &rec)) { + return gps_errno; + } + switch(gps_category_type) { + case pD120: + GPS_D120_Get(i,(char *) rec->data); + break; + } + } + if(!GPS_Packet_Read(fd, &rec)) + return gps_errno; + if(!GPS_Send_Ack(fd, &tra, &rec)) + return gps_errno; + + if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) + { + GPS_Error("A101_Get: Error transferring waypoints. Expected %d completion code. Got %d. %d of %d received", LINK_ID[gps_link_type].Pid_Xfer_Cmplt, rec->type, i, n); + return FRAMING_ERROR; + } + + + if(!GPS_Device_Off(fd)) + return gps_errno; + + return 1; + +} /* @funcstatic GPS_D100_Get ********************************************* ** @@ -1325,7 +1390,7 @@ static void GPS_D109_Get(GPS_PWay *way, UC *s, int protoid) p=s; - (*way)->prot = 109; + (*way)->prot = protoid; (*way)->wpt_class = *p++; (*way)->colour = *p++; (*way)->dspl = *p++; @@ -1352,9 +1417,26 @@ static void GPS_D109_Get(GPS_PWay *way, UC *s, int protoid) p += 4; /* Skip over "outbound link ete in seconds */ if (protoid == 110) { - p += 4; /* skip float temp */ - p += 4; /* skip longword time */ - p += 2; /* skip int "category membership " */ + float gps_temp; + int gps_time; + gps_temp = GPS_Util_Get_Float(p); + p+=4; + if (gps_temp <= 1.0e24) { + (*way)->temperature_populated = 1; + (*way)->temperature = gps_temp; + } + + gps_time = GPS_Util_Get_Uint(p); + p+=4; + /* The spec says that 0xffffffff is unknown, but the 60CSX with + * firmware 2.5.0 writes zero. + */ + if (gps_time != 0xffffffff && gps_time != 0) { + (*way)->time_populated = 1; + (*way)->time = GPS_Math_Gtime_To_Utime(gps_time); + } + (*way)->category = GPS_Util_Get_Short(p); + p += 2; } q = (UC *) (*way)->ident; @@ -1622,6 +1704,32 @@ static void GPS_D155_Get(GPS_PWay *way, UC *s) return; } +/* + * We'll cheat for now. We know there are no more than 16 categories + * as of this writing for no data type exposes more than 16 bits in the + * bitmask of categories. + */ +static char categories[16][17]; +/* + * Read descriptor s into category number N; + */ +static +void GPS_D120_Get(int cat_num, char *s) +{ + /* we're guaranteed to have no more than 16 chars plus a + * null terminator. + * + * If the unit returned no string, the user has not configured one, + * so mimic the behaviour of the 276/296. + */ + + if (*s) { + strncpy(categories[cat_num], s, sizeof (categories[0])); + } else { + snprintf(categories[cat_num], sizeof (categories[0]), + "Category %d", cat_num+1); + } +} /* @funcstatic GPS_D100_Send ******************************************* @@ -2044,14 +2152,15 @@ static void GPS_D109_Send(UC *data, GPS_PWay way, int32 *len, int protoid) GPS_Util_Put_Float(p, temp); p += 4; - if (way->Time_populated) { - GPS_Util_Put_Uint(p,GPS_Math_Utime_To_Gtime(way->Time)); + if (way->time_populated) { + GPS_Util_Put_Uint(p,GPS_Math_Utime_To_Gtime(way->time)); p+=sizeof(uint32); } else { for(i=0;i<4;++i) *p++ = 0xff; /* unknown time*/ } - for(i=0;i<2;++i) *p++ = 0x00; /* D110 category */ + GPS_Util_Put_Short(p, (US) way->category);; /* D110 category */ + p += 2; } q = (UC *) way->ident; @@ -2334,14 +2443,14 @@ static void GPS_D155_Send(UC *data, GPS_PWay way, int32 *len) int32 GPS_A200_Get(const char *port, GPS_PWay **way) { static UC data[2]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 n; int32 i; - if(!GPS_Serial_On(port,&fd)) + if(!GPS_Device_On(port,&fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -2489,7 +2598,7 @@ int32 GPS_A200_Get(const char *port, GPS_PWay **way) GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return n; @@ -2509,14 +2618,14 @@ int32 GPS_A200_Get(const char *port, GPS_PWay **way) int32 GPS_A201_Get(const char *port, GPS_PWay **way) { static UC data[2]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 n; int32 i; - if(!GPS_Serial_On(port,&fd)) + if(!GPS_Device_On(port,&fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -2682,7 +2791,7 @@ int32 GPS_A201_Get(const char *port, GPS_PWay **way) GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return n; @@ -2703,14 +2812,14 @@ int32 GPS_A201_Get(const char *port, GPS_PWay **way) int32 GPS_A200_Send(const char *port, GPS_PWay *way, int32 n) { UC data[GPS_ARB_LEN]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 i; int32 len; UC method; - if(!GPS_Serial_On(port,&fd)) + if(!GPS_Device_On(port,&fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -2831,7 +2940,7 @@ int32 GPS_A200_Send(const char *port, GPS_PWay *way, int32 n) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -2852,14 +2961,14 @@ int32 GPS_A200_Send(const char *port, GPS_PWay *way, int32 n) int32 GPS_A201_Send(const char *port, GPS_PWay *way, int32 n) { UC data[GPS_ARB_LEN]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 i; int32 len; UC method; - if(!GPS_Serial_On(port,&fd)) + if(!GPS_Device_On(port,&fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -3000,7 +3109,7 @@ int32 GPS_A201_Send(const char *port, GPS_PWay *way, int32 n) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -3232,7 +3341,7 @@ static void GPS_D210_Send(UC *data, GPS_PWay way, int32 *len) int32 GPS_A300_Get(const char *port, GPS_PTrack **trk) { static UC data[2]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 n; @@ -3250,7 +3359,7 @@ int32 GPS_A300_Get(const char *port, GPS_PTrack **trk) return GPS_UNSUPPORTED; } - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -3281,7 +3390,6 @@ int32 GPS_A300_Get(const char *port, GPS_PTrack **trk) for(i=0;itype == LINK_ID[gps_link_type].Pid_Trk_Hdr) { switch(gps_trk_hdr_type) @@ -3419,6 +3525,7 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk) GPS_D302b_Get(&((*trk)[i]),rec->data); break; case pD303: + case pD304: GPS_D303b_Get(&((*trk)[i]),rec->data); break; default: @@ -3431,7 +3538,6 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk) return gps_errno; if(!GPS_Send_Ack(fd, &tra, &rec)) return gps_errno; - if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt) { GPS_Error("A301_Get: Error transferring tracks"); @@ -3447,7 +3553,7 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return n; @@ -3470,7 +3576,7 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk) int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n) { UC data[GPS_ARB_LEN]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 i; @@ -3486,7 +3592,7 @@ int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n) return GPS_UNSUPPORTED; } - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -3543,7 +3649,7 @@ int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -3564,7 +3670,7 @@ int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n) int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n) { UC data[GPS_ARB_LEN]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 i; @@ -3581,7 +3687,7 @@ int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n) return GPS_UNSUPPORTED; } - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -3665,7 +3771,7 @@ int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -3683,7 +3789,7 @@ int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n) ** ** @return [int32] number of entries read ************************************************************************/ -int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, int32 fd) +int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, gpsdevh *fd) { GPS_PPacket tra; GPS_PPacket rec; @@ -3795,7 +3901,7 @@ void GPS_D302b_Get(GPS_PTrack *trk, UC *data) { UC *p; uint32 t; - double temp; + double gps_temp; p=data; @@ -3821,7 +3927,12 @@ void GPS_D302b_Get(GPS_PTrack *trk, UC *data) /* The only difference between 302 and 301 is the presence of temp * in the middle. Nice planning, eh? */ - temp = GPS_Util_Get_Float(p); + gps_temp = GPS_Util_Get_Float(p); + if (gps_temp <= 1.0e24) { + (*trk)->temperature_populated = 1; + (*trk)->temperature = gps_temp; + } + p+=sizeof(float); (*trk)->tnew = *p; @@ -3845,7 +3956,7 @@ void GPS_D303b_Get(GPS_PTrack *trk, UC *data) uint32 t; uint32 raw_lat, raw_lon; int lat_undefined, lon_undefined; - +int i; p=data; /* Latitude and longitude are sometimes invalid (0x7fffffff or @@ -3869,10 +3980,19 @@ void GPS_D303b_Get(GPS_PTrack *trk, UC *data) (*trk)->lon = GPS_Math_Semi_To_Deg(raw_lon); p+=sizeof(int32); + /* + * Let the caller decide if it wants to toss trackpionts with only + * hear and/or time data. + */ + if (lat_undefined || lon_undefined) { + (*trk)->no_latlon = 1; + } + if (lat_undefined != lon_undefined) GPS_Warning("GPS_D303b_Get: assumption (lat_undefined == lon_undefined) violated"); t = GPS_Util_Get_Uint(p); + if(!t || t==0x7fffffff || t==0xffffffff) (*trk)->Time=0; else @@ -3886,12 +4006,23 @@ void GPS_D303b_Get(GPS_PTrack *trk, UC *data) p+=sizeof(float); /* Heartrate is reported as 0 if there is no signal from - * a heartrate monitor. A uint32 is a bit overkill, even - * for me in my state of fitness. Perhaps this is actually - * a char or uint16, leaving room for a trk_seg bool at the end? + * a heartrate monitor. + * 305 and 304 are identical until now. */ - (*trk)->heartrate = GPS_Util_Get_Uint(p); - p+=sizeof(uint32); + switch (gps_trk_type) { + case pD304: + p+=4; /* A float indicating number of meters travelled. */ + (*trk)->heartrate = (*p++); + /* crank cadence, RPM, 0xff if invalid. */ + p++; + /* sensor present. Boolean */ + p++; + + break; + case pD303: + (*trk)->heartrate = *p++; + break; + } /* There doesn't seem to be a trk_seg bool, or at least I've not * observed it yet. One possibility is to start a new segment @@ -3948,6 +4079,7 @@ void GPS_D311_Get(GPS_PTrack *trk, UC *s) /* Forerunner */ identifier = GPS_Util_Get_Short(s); sprintf((*trk)->trk_ident, "%d", identifier); + (*trk)->tnew = 1; return; } @@ -4111,7 +4243,7 @@ static void GPS_A300_Encode(UC *s, GPS_PTrack trk) int32 GPS_A400_Get(const char *port, GPS_PWay **way) { static UC data[2]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 n; @@ -4121,7 +4253,7 @@ int32 GPS_A400_Get(const char *port, GPS_PWay **way) return GPS_UNSUPPORTED; - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -4137,13 +4269,13 @@ int32 GPS_A400_Get(const char *port, GPS_PWay **way) if(!GPS_Get_Ack(fd, &tra, &rec)) return gps_errno; - if(!GPS_Serial_Chars_Ready(fd)) + if(!GPS_Device_Chars_Ready(fd)) { GPS_Warning("A400 (ppx) protocol not supported"); GPS_Packet_Del(&rec); GPS_Packet_Del(&tra); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return GPS_UNSUPPORTED; @@ -4253,7 +4385,7 @@ int32 GPS_A400_Get(const char *port, GPS_PWay **way) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return n; @@ -4274,7 +4406,7 @@ int32 GPS_A400_Get(const char *port, GPS_PWay **way) int32 GPS_A400_Send(const char *port, GPS_PWay *way, int32 n) { UC data[GPS_ARB_LEN]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 i; @@ -4283,7 +4415,7 @@ int32 GPS_A400_Send(const char *port, GPS_PWay *way, int32 n) if(gps_prx_waypt_transfer == -1) return GPS_UNSUPPORTED; - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -4380,7 +4512,7 @@ int32 GPS_A400_Send(const char *port, GPS_PWay *way, int32 n) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -4637,14 +4769,14 @@ static void GPS_D450_Send(UC *data, GPS_PWay way, int32 *len) int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm) { static UC data[2]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 n; int32 i; int32 ret; - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -4708,7 +4840,7 @@ int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return ret; @@ -4731,7 +4863,7 @@ int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm) int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n) { UC data[GPS_ARB_LEN]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 i; @@ -4740,7 +4872,7 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n) int32 posnsent; int32 ret; - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -4829,7 +4961,7 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n) * the time. Note that the time sent is held in gps_save_time * global */ - if(GPS_Serial_Wait(fd)) + if(GPS_Device_Wait(fd)) { if(!GPS_Packet_Read(fd, &rec)) return gps_errno; @@ -4855,7 +4987,7 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n) * the position. Note that the posn sent is held in gps_save_lat * and gps_save_lon global! */ - if(GPS_Serial_Wait(fd)) + if(GPS_Device_Wait(fd)) { if(!GPS_Packet_Read(fd, &rec)) return gps_errno; @@ -4891,7 +5023,7 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -4909,7 +5041,7 @@ int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n) ** ** @return [int32] number of entries read ************************************************************************/ -static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) +static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd) { GPS_PPacket tra; GPS_PPacket rec; @@ -4961,7 +5093,7 @@ static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) ** ** @return [int32] number of entries read ************************************************************************/ -static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) +static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd) { GPS_PPacket tra; GPS_PPacket rec; @@ -5013,7 +5145,7 @@ static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) ** ** @return [int32] number of entries read ************************************************************************/ -static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) +static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd) { GPS_PPacket tra; GPS_PPacket rec; @@ -5064,7 +5196,7 @@ static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) ** ** @return [int32] number of entries read ************************************************************************/ -static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, int32 fd) +static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd) { GPS_PPacket tra; GPS_PPacket rec; @@ -5309,12 +5441,12 @@ static void GPS_A500_Encode(UC *s, GPS_PAlmanac alm) time_t GPS_A600_Get(const char *port) { static UC data[2]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; time_t ret; - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -5347,7 +5479,7 @@ time_t GPS_A600_Get(const char *port) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return ret; @@ -5368,13 +5500,13 @@ time_t GPS_A600_Get(const char *port) ************************************************************************/ int32 GPS_A600_Send(const char *port, time_t Time) { - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; int32 posnsent=0; int32 ret=0; - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -5401,7 +5533,7 @@ int32 GPS_A600_Send(const char *port, time_t Time) * the position. Note that the posn sent is held in gps_save_lat * and gps_save_lon globals! */ - if(GPS_Serial_Wait(fd)) + if(GPS_Device_Wait(fd)) { if(!GPS_Packet_Read(fd, &rec)) return gps_errno; @@ -5431,7 +5563,7 @@ int32 GPS_A600_Send(const char *port, time_t Time) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -5520,11 +5652,11 @@ void GPS_D600_Send(GPS_PPacket *packet, time_t Time) int32 GPS_A700_Get(const char *port, double *lat, double *lon) { static UC data[2]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -5558,7 +5690,7 @@ int32 GPS_A700_Get(const char *port, double *lat, double *lon) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -5578,11 +5710,11 @@ int32 GPS_A700_Get(const char *port, double *lat, double *lon) ************************************************************************/ int32 GPS_A700_Send(const char *port, double lat, double lon) { - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -5608,7 +5740,7 @@ int32 GPS_A700_Send(const char *port, double lat, double lon) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -5687,13 +5819,13 @@ void GPS_D700_Send(GPS_PPacket *packet, double lat, double lon) ** ** @return [int32] success ************************************************************************/ -int32 GPS_A800_On(const char *port, int32 *fd) +int32 GPS_A800_On(const char *port, gpsdevh **fd) { static UC data[2]; GPS_PPacket tra; GPS_PPacket rec; - if(!GPS_Serial_On(port, fd)) + if(!GPS_Device_On(port, fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -5729,7 +5861,7 @@ int32 GPS_A800_On(const char *port, int32 *fd) ** ** @return [int32] success ************************************************************************/ -int32 GPS_A800_Off(const char *port, int32 *fd) +int32 GPS_A800_Off(const char *port, gpsdevh **fd) { static UC data[2]; GPS_PPacket tra; @@ -5755,8 +5887,8 @@ int32 GPS_A800_Off(const char *port, int32 *fd) GPS_Packet_Del(&rec); GPS_Packet_Del(&tra); - if(!GPS_Serial_Off(port, *fd)) - return gps_errno; +// if(!GPS_Device_Off(*fd)) +// return gps_errno; return 1; } @@ -5771,7 +5903,7 @@ int32 GPS_A800_Off(const char *port, int32 *fd) ** ** @return [int32] success ************************************************************************/ -int32 GPS_A800_Get(int32 *fd, GPS_PPvt_Data *packet) +int32 GPS_A800_Get(gpsdevh **fd, GPS_PPvt_Data *packet) { GPS_PPacket tra; GPS_PPacket rec; @@ -5878,7 +6010,7 @@ void GPS_D800_Get(GPS_PPacket packet, GPS_PPvt_Data *pvt) int32 GPS_A906_Get(const char *port, GPS_OLap_Data **lap) { static UC data[2]; - int32 fd; + gpsdevh *fd; GPS_PPacket lappkt; GPS_PPacket recpkt; int32 i, n; @@ -5886,7 +6018,7 @@ int32 GPS_A906_Get(const char *port, GPS_OLap_Data **lap) if (gps_lap_transfer == -1) return GPS_UNSUPPORTED; - if (!GPS_Serial_On(port, &fd)) + if (!GPS_Device_On(port, &fd)) return gps_errno; if (!(lappkt = GPS_Packet_New() ) || !(recpkt = GPS_Packet_New())) @@ -5934,7 +6066,7 @@ int32 GPS_A906_Get(const char *port, GPS_OLap_Data **lap) GPS_Packet_Del(&lap); GPS_Packet_Del(&rec); - if (!GPS_Serial_Off(port, fd)) + if (!GPS_Device_Off(fd)) return gps_errno; return ret; @@ -6012,6 +6144,7 @@ Get_Pkt_Type(unsigned char p, unsigned char d0, const char **xinfo) case 50: *xinfo = "Xfer PVT Stop"; break; case 92: *xinfo = "Flight Records"; break; case 117: *xinfo = "Xfer Laps"; break; + case 121: *xinfo = "Xfer Categories"; break; default: *xinfo = "Unknown"; } return "CMDDAT"; @@ -6056,5 +6189,7 @@ Get_Pkt_Type(unsigned char p, unsigned char d0, const char **xinfo) return "SESREQ"; if (p == GUSB_SESSION_ACK) return "SESACK"; + if (p == 152) + return "WPTCAT"; return "UNKNOWN"; } diff --git a/gpsbabel/jeeps/gpsapp.h b/gpsbabel/jeeps/gpsapp.h index a8f6ffb13..38a628f32 100644 --- a/gpsbabel/jeeps/gpsapp.h +++ b/gpsbabel/jeeps/gpsapp.h @@ -12,6 +12,7 @@ extern "C" int32 GPS_Init(const char *port); int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int ct, GPS_PWay *)); +int32 GPS_A101_Get(const char *port); int32 GPS_A100_Send(const char *port, GPS_PWay *way, int32 n, int (*cb)(GPS_PWay *)); int32 GPS_A200_Get(const char *port, GPS_PWay **way); @@ -24,7 +25,7 @@ int32 GPS_A301_Get(const char *port, GPS_PTrack **trk); int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n); int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n); -int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, int32 fd); +int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, gpsdevh *h); void GPS_D300b_Get(GPS_PTrack *trk, UC *data); void GPS_D301b_Get(GPS_PTrack *trk, UC *data); void GPS_D302b_Get(GPS_PTrack *trk, UC *data); @@ -51,9 +52,9 @@ int32 GPS_A700_Send(const char *port, double lat, double lon); void GPS_D700_Get(GPS_PPacket packet, double *lat, double *lon); void GPS_D700_Send(GPS_PPacket *packet, double lat, double lon); -int32 GPS_A800_On(const char *port, int32 *fd); -int32 GPS_A800_Off(const char *port, int32 *fd); -int32 GPS_A800_Get(int32 *fd, GPS_PPvt_Data *packet); +int32 GPS_A800_On(const char *port, gpsdevh **fd); +int32 GPS_A800_Off(const char *port, gpsdevh **fd); +int32 GPS_A800_Get(gpsdevh **fd, GPS_PPvt_Data *packet); void GPS_D800_Get(GPS_PPacket packet, GPS_PPvt_Data *pvt); const char * Get_Pkt_Type(unsigned char p, unsigned char d0, const char **xinfo); diff --git a/gpsbabel/jeeps/gpscom.c b/gpsbabel/jeeps/gpscom.c index b3d6b3e05..e8a2874e1 100644 --- a/gpsbabel/jeeps/gpscom.c +++ b/gpsbabel/jeeps/gpscom.c @@ -4,6 +4,7 @@ ** @author Copyright (C) 1999 Alan Bleasby ** @version 1.0 ** @modified Dec 28 1999 Alan Bleasby. First version +** @modified Copyright (C) 2005, 2006 Robert Lipe ** @@ ** ** This library is free software; you can redistribute it and/or @@ -35,15 +36,13 @@ int32 GPS_Command_Off(const char *port) { static UC data[2]; - int32 fd; + gpsdevh *fd; GPS_PPacket tra; GPS_PPacket rec; GPS_Util_Little(); - gps_is_usb = (0 == strncmp(port, "usb:", 4)); - - if(!GPS_Serial_On(port, &fd)) + if(!GPS_Device_On(port, &fd)) return gps_errno; if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New())) @@ -57,7 +56,7 @@ int32 GPS_Command_Off(const char *port) if(!GPS_Write_Packet(fd,tra)) return gps_errno; - if(!GPS_Serial_Chars_Ready(fd)) + if(!GPS_Device_Chars_Ready(fd)) { if(!GPS_Get_Ack(fd, &tra, &rec)) return gps_errno; @@ -67,7 +66,7 @@ int32 GPS_Command_Off(const char *port) GPS_Packet_Del(&tra); GPS_Packet_Del(&rec); - if(!GPS_Serial_Off(port, fd)) + if(!GPS_Device_Off(fd)) return gps_errno; return 1; @@ -88,6 +87,19 @@ int32 GPS_Command_Get_Waypoint(const char *port, GPS_PWay **way, int (*cb)(int, { int32 ret=0; + /* + * It's a bit tacky to do this up front without ticking the + * progress meter, but this come in pretty quickly... + */ + if (gps_category_transfer) { + ret = GPS_A101_Get(port); + if (!ret) { +fatal("blah"); + return PROTOCOL_ERROR; + } + + } + switch(gps_waypt_transfer) { case pA100: @@ -224,7 +236,7 @@ int32 GPS_Command_Get_Track(const char *port, GPS_PTrack **trk) ret = GPS_A301_Get(port,trk); break; default: - GPS_Error("Get_Track: Unknown track protocol\n"); + GPS_Error("Get_Track: Unknown track protocol %d\n", gps_trk_transfer); return PROTOCOL_ERROR; } @@ -412,6 +424,12 @@ time_t GPS_Command_Get_Time(const char *port) case pA600: ret = GPS_A600_Get(port); break; + /* + * If the unit doesn't support it (i.e. a C320 in charging mode), + * but don't treat as error; return as zero. + */ + case -1: + return 0; default: GPS_Error("Get_Time: Unknown date/time protocol"); return PROTOCOL_ERROR; @@ -472,6 +490,13 @@ int32 GPS_Command_Get_Position(const char *port, double *lat, double *lon) case pA700: ret = GPS_A700_Get(port,lat,lon); break; + /* + * If the unit doesn't support it (i.e. a C320 in charging mode), + * zero lat/lon, but don't treat as error. + */ + case -1: + *lat = *lon = 0.0; + break; default: GPS_Error("Get_Position: Unknown position protocol"); return PROTOCOL_ERROR; @@ -521,7 +546,7 @@ int32 GPS_Command_Send_Position(const char *port, double lat, double lon) ** @return [int32] success if supported and GPS starts sending ************************************************************************/ -int32 GPS_Command_Pvt_On(const char *port, int32 *fd) +int32 GPS_Command_Pvt_On(const char *port, gpsdevh **fd) { int32 ret=0; @@ -556,7 +581,7 @@ int32 GPS_Command_Pvt_On(const char *port, int32 *fd) ** @return [int32] success ************************************************************************/ -int32 GPS_Command_Pvt_Off(const char *port, int32 *fd) +int32 GPS_Command_Pvt_Off(const char *port, gpsdevh **fd) { int32 ret=0; @@ -589,7 +614,7 @@ int32 GPS_Command_Pvt_Off(const char *port, int32 *fd) ** @return [int32] success ************************************************************************/ -int32 GPS_Command_Pvt_Get(int32 *fd, GPS_PPvt_Data *pvt) +int32 GPS_Command_Pvt_Get(gpsdevh **fd, GPS_PPvt_Data *pvt) { int32 ret=0; diff --git a/gpsbabel/jeeps/gpscom.h b/gpsbabel/jeeps/gpscom.h index e8bbe1d2a..40f49c219 100644 --- a/gpsbabel/jeeps/gpscom.h +++ b/gpsbabel/jeeps/gpscom.h @@ -18,9 +18,9 @@ int32 GPS_Command_Send_Time(const char *port, time_t Time); int32 GPS_Command_Get_Position(const char *port, double *lat, double *lon); int32 GPS_Command_Send_Position(const char *port, double lat, double lon); -int32 GPS_Command_Pvt_On(const char *port, int32 *fd); -int32 GPS_Command_Pvt_Off(const char *port, int32 *fd); -int32 GPS_Command_Pvt_Get(int32 *fd, GPS_PPvt_Data *pvt); +int32 GPS_Command_Pvt_On(const char *port, gpsdevh **fd); +int32 GPS_Command_Pvt_Off(const char *port, gpsdevh **fd); +int32 GPS_Command_Pvt_Get(gpsdevh **fd, GPS_PPvt_Data *pvt); int32 GPS_Command_Get_Almanac(const char *port, GPS_PAlmanac **alm); int32 GPS_Command_Send_Almanac(const char *port, GPS_PAlmanac *alm, int32 n); diff --git a/gpsbabel/jeeps/gpsdevice.c b/gpsbabel/jeeps/gpsdevice.c new file mode 100644 index 000000000..90c841f1b --- /dev/null +++ b/gpsbabel/jeeps/gpsdevice.c @@ -0,0 +1,86 @@ +/* + Abstraction of underlying device types, serial or USB. OS agnostic.. + + Copyright (C) 2006 Robert Lipe, robertlipe@usa.net + + This program is free software{} you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation{} either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY{} without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program{} if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "gps.h" +#include "gpsdevice.h" +#include "gpsserial.h" + +extern gps_device_ops gps_serial_ops; +extern gps_device_ops gps_usb_ops; +gps_device_ops *ops = NULL; + +int32 GPS_Device_On(const char *port, gpsdevh **fd) +{ + gps_is_usb = (0 == case_ignore_strncmp(port, "usb:", 4)); + + if (gps_is_usb) { + ops = &gps_usb_ops; + } else { + ops = &gps_serial_ops; + } + + return (ops->Device_On)(port, fd); +} + +int32 GPS_Device_Off(gpsdevh * fd) +{ + return (ops->Device_Off)(fd); +} + +int32 GPS_Device_Wait(gpsdevh * fd) +{ + return (ops->Device_Wait)(fd); +} + +int32 GPS_Device_Chars_Ready(gpsdevh * fd) +{ + return (ops->Device_Chars_Ready)(fd); +} + +int32 GPS_Device_Flush(gpsdevh * fd) +{ + return (ops->Device_Flush)(fd); +} + +int32 GPS_Write_Packet(gpsdevh * fd, GPS_PPacket packet) +{ + return (ops->Write_Packet)(fd, packet); +} + +int32 GPS_Packet_Read(gpsdevh * fd, GPS_PPacket *packet) +{ + return (ops->Read_Packet)(fd, packet); +} + +int32 GPS_Send_Ack(gpsdevh * fd, GPS_PPacket *tra, GPS_PPacket *rec) +{ + return (ops->Send_Ack)(fd, tra, rec); +} + +int32 GPS_Get_Ack(gpsdevh * fd, GPS_PPacket *tra, GPS_PPacket *rec) +{ + return (ops->Get_Ack)(fd, tra, rec); +} + +void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n) +{ + (ops->Make_Packet)(packet, type, data, n); +} diff --git a/gpsbabel/jeeps/gpsdevice.h b/gpsbabel/jeeps/gpsdevice.h new file mode 100644 index 000000000..eb5d53d96 --- /dev/null +++ b/gpsbabel/jeeps/gpsdevice.h @@ -0,0 +1,73 @@ +/* + Abstraction of underlying device types. + + Copyright (C) 2006 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef gpsdevice_h +#define gpsdevice_h + +typedef struct gpsdevh gpsdevh; + +#include "gps.h" + +#define usecDELAY 180000 /* Microseconds before GPS sends A001 */ + + +int32 GPS_Device_Chars_Ready(gpsdevh *fd); +int32 GPS_Device_On(const char *port, gpsdevh **fd); +int32 GPS_Device_Off(gpsdevh *fd); +int32 GPS_Device_Wait(gpsdevh * fd); +int32 GPS_Device_Flush(gpsdevh * fd); +int32 GPS_Device_Read(int32 ignored, void *ibuf, int size); +int32 GPS_Device_Write(int32 ignored, const void *obuf, int size); +void GPS_Device_Error(char *hdr, ...); +int32 GPS_Write_Packet(gpsdevh *fd, GPS_PPacket packet); +int32 GPS_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec); +int32 GPS_Packet_Read(gpsdevh *fd, GPS_PPacket *packet); +int32 GPS_Get_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec); + +typedef int32 (*gps_device_op)(gpsdevh *); +typedef int32 (*gps_device_op5)(const char *, gpsdevh **fd); +typedef int32 (*gps_device_op10)(gpsdevh * fd, GPS_PPacket *tra, GPS_PPacket *rec); +typedef int32 (*gps_device_op12)(gpsdevh * fd, GPS_PPacket packet); +typedef int32 (*gps_device_op13)(gpsdevh * fd, GPS_PPacket *packet); +typedef void (*gps_device_op14)(GPS_PPacket *packet, UC type, UC *data, int16 n); +typedef struct { + gps_device_op5 Device_On; + gps_device_op Device_Off; + gps_device_op Device_Chars_Ready; + gps_device_op Device_Wait; + gps_device_op Device_Flush; + gps_device_op10 Send_Ack; + gps_device_op10 Get_Ack; + gps_device_op13 Read_Packet; + gps_device_op14 Make_Packet; + gps_device_op12 Write_Packet; +} gps_device_ops; + +#endif /* gpsdevice.h */ + +#ifdef __cplusplus +} +#endif diff --git a/gpsbabel/jeeps/gpsdevice_ser.c b/gpsbabel/jeeps/gpsdevice_ser.c new file mode 100644 index 000000000..29ff476e6 --- /dev/null +++ b/gpsbabel/jeeps/gpsdevice_ser.c @@ -0,0 +1,37 @@ +/* + Serial operations. + + Copyright (C) 2006 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "gpsdevice.h" +#include "gpsserial.h" +#include "gpsread.h" + +gps_device_ops gps_serial_ops = { + GPS_Serial_On, + GPS_Serial_Off, + GPS_Serial_Chars_Ready, + GPS_Serial_Wait, + GPS_Serial_Flush, + GPS_Serial_Send_Ack, + GPS_Serial_Get_Ack, + GPS_Serial_Packet_Read, + GPS_Serial_Make_Packet, + GPS_Serial_Write_Packet, +}; diff --git a/gpsbabel/jeeps/gpsdevice_usb.c b/gpsbabel/jeeps/gpsdevice_usb.c new file mode 100644 index 000000000..dd578c829 --- /dev/null +++ b/gpsbabel/jeeps/gpsdevice_usb.c @@ -0,0 +1,59 @@ +/* + USB operations. + + Copyright (C) 2006 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "gpsdevice.h" +#include "garminusb.h" +#include "gpsusbint.h" +#include "gpsusbcommon.h" + +static int32 success_stub(void) +{ + return 1; +} + +static int32 gdu_on(const char *port, gpsdevh **fd) +{ + return gusb_init(port, fd); +} + +static int32 gdu_off(gpsdevh *dh) +{ + return gusb_close(dh); +} + +static int32 gdu_read(gpsdevh *fd, GPS_PPacket *packet) +{ + /* Default is to eat bulk request packets. */ + return GPS_Packet_Read_usb(fd, packet, 1); +} + +gps_device_ops gps_usb_ops = { + gdu_on, + gdu_off, + (gps_device_op) success_stub, + (gps_device_op) success_stub, + (gps_device_op) success_stub, + (gps_device_op10) success_stub, + (gps_device_op10) success_stub, + gdu_read, + GPS_Make_Packet_usb, + GPS_Write_Packet_usb +}; diff --git a/gpsbabel/jeeps/gpslibusb.c b/gpsbabel/jeeps/gpslibusb.c index 0151720b9..b0c25669b 100644 --- a/gpsbabel/jeeps/gpslibusb.c +++ b/gpsbabel/jeeps/gpslibusb.c @@ -1,7 +1,7 @@ /* Physical/OS USB layer to talk to libusb. - Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + Copyright (C) 2004, 2005, 2006 Robert Lipe, robertlipe@usa.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,7 +26,9 @@ #if HAVE_LIBUSB #include #include "gps.h" +#include "gpslibusb.h" #include "garminusb.h" +#include "gpsusbcommon.h" #define GARMIN_VID 0x91e @@ -39,57 +41,30 @@ * coalescion into packets anyway becuase of their serial background) will * compensate. */ -#define TMOUT_I 0100 /* Milliseconds to timeout intr pipe access. */ +#define TMOUT_I 3000 /* Milliseconds to timeout intr pipe access. */ +#define TMOUT_B 3000 /* Milliseconds to timeout bulk pipe access. */ -int gusb_intr_in_ep; -int gusb_bulk_out_ep; -int gusb_bulk_in_ep; -static const char oinit[12] = {0, 0, 0, 0, 0x05, 0, 0, 0, 0, 0, 0, 0}; -garmin_usb_packet iresp; - -static struct usb_bus *busses; -static usb_dev_handle *udev; -static void garmin_usb_scan(void); -static void garmin_usb_syncup(void); - -int -gusb_init(const char *portname) -{ -// usb_set_debug(99); - usb_init(); - usb_find_busses(); - usb_find_devices(); - busses = usb_get_busses(); - garmin_usb_scan(); - - return 1; -} +/* + * TODO: this should all be moved into libusbdata in gpslibusb.h, + * allocated once here in gusb_start, and deallocated at the end. + */ +static int gusb_intr_in_ep; +static int gusb_bulk_out_ep; +static int gusb_bulk_in_ep; -static void dump(char *msg, const unsigned char *in, int r) -{ - int i; - printf("%s: %d\n", msg, r); - for (i = 0; i < r; i++) { - printf ("%02x ", in[i]); - } - if (r) printf("\n"); - for (i = 0; i < r; i++) { - printf ("%c", isalnum(in[i]) ? in[i] : '.'); - } - if (r) printf("\n"); -} +// static struct usb_bus *busses; +static usb_dev_handle *udev; +static void garmin_usb_scan(libusb_unit_data *, int); -int -gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz) +static int +gusb_libusb_send(const garmin_usb_packet *opkt, size_t sz) { int r; + + r = usb_bulk_write(udev, gusb_bulk_out_ep, (char *)(void *)opkt->dbuf, sz, TMOUT_B); - r = usb_bulk_write(udev, gusb_bulk_out_ep, (char *)(void *)opkt->dbuf, sz, TMOUT_I); - if (gps_show_bytes) { - dump ("Sent", &opkt->dbuf[0], r); - } - if (r != sz) { + if (r != (int) sz) { fprintf(stderr, "Bad cmdsend r %d sz %d\n", r, sz); if (r < 0) { fatal("usb_bulk_write failed. '%s'\n", @@ -99,42 +74,37 @@ gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz) return r; } -int -gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz) +static int +gusb_libusb_get(garmin_usb_packet *ibuf, size_t sz) { unsigned char *buf = &ibuf->dbuf[0]; - unsigned char *obuf = buf; - int r = -1, tsz = 0; + int r = -1; r = usb_interrupt_read(udev, gusb_intr_in_ep, (char *) buf, sz, TMOUT_I); + return r; +} - tsz = r; - - if (gps_show_bytes) { - int i; - const char *m1, *m2; - printf("RX [%d]:", tsz); - for(i=0;idbuf[0]; - m1 = Get_Pkt_Type(ibuf->gusb_pkt.pkt_id[0], ibuf->gusb_pkt.databuf[0], &m2); - GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); - printf("\n"); - } + r = usb_bulk_read(udev, gusb_bulk_in_ep, (char *) buf, sz, TMOUT_B); - return (r); + return r; } -void -garmin_usb_teardown(void) + +static int +gusb_teardown(const char *pname) { if (udev) { usb_release_interface(udev, 0); usb_close(udev); udev = NULL; } + return 0; } void @@ -143,11 +113,10 @@ garmin_usb_start(struct usb_device *dev) int i; if (udev) return; - /* - * Linux _requires_ the reset. OSX doesn't work if we DO reset it. - * I really should study this more, but for now, we'll just avoid the - * reset on Apple's OSX. + * Linux _requires_ the reset. OSX doesn't work if we + * DO reset it. I really should study this more, but for + * now, we'll just avoid the reset on Apple's OSX. */ #if !defined (__APPLE__) udev = usb_open(dev); @@ -156,21 +125,21 @@ garmin_usb_start(struct usb_device *dev) #endif /* APPLE */ udev = usb_open(dev); - atexit(garmin_usb_teardown); + atexit((void(*)())gusb_teardown); + if (!udev) { fatal("usb_open failed\n"); } /* * Hrmph. No iManufacturer or iProduct headers.... */ if (usb_set_configuration(udev, 1) < 0) { - fatal("usb_set_configuration failed\n"); + fatal("usb_set_configuration failed: %s\n", usb_strerror()); } if (usb_claim_interface(udev, 0) < 0) { -// abort(); + fatal("Claim interfaced failed: %s\n", usb_strerror()); } - for (i = 0; i < dev->config->interface->altsetting->bNumEndpoints; i++) { struct usb_endpoint_descriptor * ep; ep = &dev->config->interface->altsetting->endpoint[i]; @@ -194,49 +163,22 @@ garmin_usb_start(struct usb_device *dev) * that loop without non-zero values for all three, we're hosed. */ if (gusb_intr_in_ep && gusb_bulk_in_ep && gusb_bulk_out_ep) { - garmin_usb_syncup(); - } else { - fatal("Could not identify endpoints on USB device.\nFound endpoints Intr In %d Bulk Out %d Bulk In %d\n", gusb_intr_in_ep, gusb_bulk_out_ep, gusb_bulk_in_ep); + gusb_syncup(); + return; } - return; -} - -void -garmin_usb_syncup(void) -{ - int maxct = 5; - int maxtries; - - for (maxtries = maxct; maxtries; maxtries--) { - - le_write16(&iresp.gusb_pkt.pkt_id, 0); - le_write32(&iresp.gusb_pkt.datasz, 0); - le_write32(&iresp.gusb_pkt.databuf, 0); - - gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit)); - gusb_cmd_get(&iresp, sizeof(iresp)); - - if ((le_read16(iresp.gusb_pkt.pkt_id) == 6) && - (le_read32(iresp.gusb_pkt.datasz) == 4)) { - if (gps_show_bytes) { - fprintf(stderr, "Synced in %d\n", maxct - maxtries); - } -// fprintf(stderr, "Unit number %u\n", iresp[15] << 24 | iresp[14] << 16 | iresp[13] << 8 | iresp[12]); - return; - } - } -return; - fatal("Cannot sync up with receiver\n"); + fatal("Could not identify endpoints on USB device.\n" + "Found endpoints Intr In 0x%x Bulk Out 0x%x Bulk In %0xx\n", + gusb_intr_in_ep, gusb_bulk_out_ep, gusb_bulk_in_ep); } static -void garmin_usb_scan(void) +void garmin_usb_scan(libusb_unit_data *lud, int req_unit_number) { - int initted = 0; + int found_devices = 0; struct usb_bus *bus; - for (bus = busses; bus; bus = bus->next) { + for (bus = lud->busses; bus; bus = bus->next) { struct usb_device *dev; for (dev = bus->devices; dev; dev = dev->next) { @@ -245,14 +187,58 @@ void garmin_usb_scan(void) * we just take the easy way out for now. */ if (dev->descriptor.idVendor == GARMIN_VID) { - garmin_usb_start(dev); - initted++; + /* Nuvi */ + if (dev->descriptor.idProduct == 0x19) + continue; + if (req_unit_number < 0) { + garmin_usb_start(dev); + gusb_teardown(NULL); + } else + if (req_unit_number == found_devices) + garmin_usb_start(dev); + found_devices++; } } } - if (0 == initted) { + if (req_unit_number < 0) { + gusb_list_units(); + exit (0); + } + if (0 == found_devices) { fatal("Found no Garmin USB devices.\n"); } } + +static gusb_llops_t libusb_llops = { + gusb_libusb_get, + gusb_libusb_get_bulk, + gusb_libusb_send, + gusb_teardown +}; + +int +gusb_init(const char *portname, gpsdevh **dh) +{ + int req_unit_number = 0; + libusb_unit_data *lud = xcalloc(sizeof (libusb_unit_data), 1); + *dh = (gpsdevh*) lud; + +// usb_set_debug(99); + usb_init(); + gusb_register_ll(&libusb_llops); + + /* if "usb:N", read "N" to be the unit number. */ + if (strlen(portname) > 4) { + req_unit_number = atoi(portname + 4); + } + + usb_find_busses(); + usb_find_devices(); + lud->busses = usb_get_busses(); + garmin_usb_scan(lud, req_unit_number); + + return 1; +} + #endif /* HAVE_LIBUSB */ diff --git a/gpsbabel/jeeps/gpsmem.c b/gpsbabel/jeeps/gpsmem.c index ed070c08a..b3141dc43 100644 --- a/gpsbabel/jeeps/gpsmem.c +++ b/gpsbabel/jeeps/gpsmem.c @@ -5,6 +5,7 @@ ** @version 1.0 ** @modified December 28th 1999 Alan Bleasby. First version ** @modified June 29th 2000 Alan Bleasby. NMEA additions +** @modified Copyright (C) 2006 Robert Lipe ** @@ ** ** This library is free software; you can redistribute it and/or @@ -23,7 +24,6 @@ ** Boston, MA 02111-1307, USA. ********************************************************************/ #include "gps.h" -#include "garminusb.h" #include #include #include @@ -63,7 +63,6 @@ GPS_PPacket GPS_Packet_New(void) } - /* @func GPS_Packet_Del *********************************************** ** ** Packet destructor diff --git a/gpsbabel/jeeps/gpsprot.c b/gpsbabel/jeeps/gpsprot.c index 812437092..fabdfd89a 100644 --- a/gpsbabel/jeeps/gpsprot.c +++ b/gpsbabel/jeeps/gpsprot.c @@ -4,6 +4,7 @@ ** @author Copyright (C) 1999 Alan Bleasby ** @version 1.0 ** @modified Dec 28 1999 Alan Bleasby. First version +** @modified Copyright (C) 2006 Robert Lipe ** @@ ** ** This library is free software; you can redistribute it and/or @@ -36,7 +37,7 @@ static int32 gps_n_tag_unknown = 0; struct COMMANDDATA COMMAND_ID[2]= { { - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x31,0x32 + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x31,0x32,92,117,121 } , { diff --git a/gpsbabel/jeeps/gpsprot.h b/gpsbabel/jeeps/gpsprot.h index 60cc3c32c..f9542799d 100644 --- a/gpsbabel/jeeps/gpsprot.h +++ b/gpsbabel/jeeps/gpsprot.h @@ -33,6 +33,7 @@ struct LINKDATA UC Pid_Protocol_Array; UC Pid_Product_Rqst; UC Pid_Product_Data; + UC Pid_Wpt_Cat_Data; } ; @@ -63,7 +64,9 @@ struct COMMANDDATA UC Cmnd_Turn_Off_Pwr; UC Cmnd_Start_Pvt_Data; UC Cmnd_Stop_Pvt_Data; + UC Cmnd_FlightBook_Transfer; UC Cmnd_Transfer_Lap; + UC Cmnd_Transfer_Wpt_Cats; } ; @@ -76,6 +79,11 @@ struct COMMANDDATA #define pA100 100 int32 gps_waypt_transfer; +/* + * Waypoint category transfer protocol + */ +#define pA101 101 +int32 gps_category_transfer; /* * Route Transfer Protocol @@ -90,6 +98,7 @@ int32 gps_route_transfer; #define pA300 300 #define pA301 301 #define pA302 302 +#define pA304 304 int32 gps_trk_transfer; /* @@ -157,6 +166,11 @@ int32 gps_lap_transfer; int32 gps_rte_type; int32 gps_waypt_type; +/* + * Waypoint category types + */ +#define pD120 120 +int32 gps_category_type; /* * Rte Header Type @@ -181,6 +195,7 @@ int32 gps_rte_link_type; #define pD301 301 #define pD302 302 #define pD303 303 +#define pD304 304 int32 gps_trk_type; diff --git a/gpsbabel/jeeps/gpsread.c b/gpsbabel/jeeps/gpsread.c index 2d2f2d153..587f15c6f 100644 --- a/gpsbabel/jeeps/gpsread.c +++ b/gpsbabel/jeeps/gpsread.c @@ -4,6 +4,7 @@ ** @author Copyright (C) 1999 Alan Bleasby ** @version 1.0 ** @modified Dec 28 1999 Alan Bleasby. First version +** @modified Copyright (C) 2006 Robert Lipe ** @@ ** ** This library is free software; you can redistribute it and/or @@ -22,7 +23,7 @@ ** Boston, MA 02111-1307, USA. ********************************************************************/ #include "gps.h" -#include "gpsusbint.h" +#include "gpsserial.h" #include #include #include @@ -57,7 +58,7 @@ time_t GPS_Time_Now(void) -/* @func GPS_Packet_Read *********************************************** +/* @func GPS_Serial_Packet_Read *********************************************** ** ** Read a packet ** @@ -67,7 +68,7 @@ time_t GPS_Time_Now(void) ** @return [int32] number of bytes read **********************************************************************/ -int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet) +int32 GPS_Serial_Packet_Read(gpsdevh *fd, GPS_PPacket *packet) { time_t start; int32 n; @@ -84,10 +85,6 @@ int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet) isDLE = gpsFalse; p = (*packet)->data; - if (gps_is_usb) { - return GPS_Packet_Read_usb(fd, packet); - } - start = GPS_Time_Now(); GPS_Diag("Rx Data:"); while(GPS_Time_Now() < start+GPS_TIME_OUT) @@ -109,7 +106,7 @@ int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet) (*packet)->dle = u; if(u != DLE) { - (void) fprintf(stderr,"GPS_Packet_Read: No DLE\n"); + (void) fprintf(stderr,"GPS_Packet_Read: No DLE. Data received, but probably not a garmin packet.\n"); (void) fflush(stderr); return 0; } @@ -166,6 +163,14 @@ int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet) } m1 = Get_Pkt_Type((*packet)->type, (*packet)->data[0], &m2); + if (gps_show_bytes) { + GPS_Diag(" "); + for (i = 0; i < (*packet)->n; i++) { + char c = (*packet)->data[i]; + GPS_Diag("%c", isalnum(c) ? c : '.'); + } + GPS_Diag(" "); + } GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); return (*packet)->n; } @@ -175,7 +180,7 @@ int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet) } - GPS_Error("GPS_Packet_Read: Time-out"); + GPS_Error("GPS_Packet_Read: Timeout. No data received."); gps_errno = SERIAL_ERROR; return 0; @@ -194,13 +199,9 @@ int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet) ** @return [int32] true if ACK **********************************************************************/ -int32 GPS_Get_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec) +int32 GPS_Serial_Get_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec) { - if (gps_is_usb) { - return 1; - } - - if(!GPS_Packet_Read(fd, rec)) + if(!GPS_Serial_Packet_Read(fd, rec)) return 0; if(LINK_ID[0].Pid_Ack_Byte != (*rec)->type) diff --git a/gpsbabel/jeeps/gpsread.h b/gpsbabel/jeeps/gpsread.h index 5abd56cfa..17f3bd852 100644 --- a/gpsbabel/jeeps/gpsread.h +++ b/gpsbabel/jeeps/gpsread.h @@ -8,14 +8,10 @@ extern "C" #include "gps.h" -#include time_t GPS_Time_Now(void); -int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet); -int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet); -int32 GPS_Get_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec); -int32 ajb(int32 fd); - +int32 GPS_Serial_Packet_Read(gpsdevh *fd, GPS_PPacket *packet); +int32 GPS_Serial_Get_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec); #endif diff --git a/gpsbabel/jeeps/gpsrqst.c b/gpsbabel/jeeps/gpsrqst.c index 827559071..7203313c6 100644 --- a/gpsbabel/jeeps/gpsrqst.c +++ b/gpsbabel/jeeps/gpsrqst.c @@ -4,6 +4,7 @@ ** @author Copyright (C) 1999 Alan Bleasby ** @version 1.0 ** @modified Dec 28 1999 Alan Bleasby. First version +** @modified Copyright (C) 2006 Robert Lipe ** @@ ** ** This library is free software; you can redistribute it and/or @@ -24,8 +25,8 @@ #include "gps.h" -static int32 GPS_A600_Rqst(int32 fd, time_t Time); -static int32 GPS_A700_Rqst(int32 fd, double lat, double lon); +static int32 GPS_A600_Rqst(gpsdevh *fd, time_t Time); +static int32 GPS_A700_Rqst(gpsdevh *fd, double lat, double lon); @@ -39,7 +40,7 @@ static int32 GPS_A700_Rqst(int32 fd, double lat, double lon); ** @return [int32] true if OK ************************************************************************/ -int32 GPS_Rqst_Send_Time(int32 fd, time_t Time) +int32 GPS_Rqst_Send_Time(gpsdevh *fd, time_t Time) { time_t ret=0; @@ -67,7 +68,7 @@ int32 GPS_Rqst_Send_Time(int32 fd, time_t Time) ** ** @return [int32] success ************************************************************************/ -static int32 GPS_A600_Rqst(int32 fd, time_t Time) +static int32 GPS_A600_Rqst(gpsdevh *fd, time_t Time) { GPS_PPacket tra; GPS_PPacket rec; @@ -110,7 +111,7 @@ static int32 GPS_A600_Rqst(int32 fd, time_t Time) ** @return [int32] success ************************************************************************/ -int32 GPS_Rqst_Send_Position(int32 fd, double lat, double lon) +int32 GPS_Rqst_Send_Position(gpsdevh *fd, double lat, double lon) { int32 ret=0; @@ -139,7 +140,7 @@ int32 GPS_Rqst_Send_Position(int32 fd, double lat, double lon) ** ** @return [int32] success ************************************************************************/ -static int32 GPS_A700_Rqst(int32 fd, double lat, double lon) +static int32 GPS_A700_Rqst(gpsdevh *fd, double lat, double lon) { GPS_PPacket tra; GPS_PPacket rec; diff --git a/gpsbabel/jeeps/gpsrqst.h b/gpsbabel/jeeps/gpsrqst.h index c6398ecd0..ec0169586 100644 --- a/gpsbabel/jeeps/gpsrqst.h +++ b/gpsbabel/jeeps/gpsrqst.h @@ -9,8 +9,8 @@ extern "C" #include "gps.h" -int32 GPS_Rqst_Send_Time(int32 fd, time_t Time); -int32 GPS_Rqst_Send_Position(int32 fd, double lat, double lon); +int32 GPS_Rqst_Send_Time(gpsdevh *fd, time_t Time); +int32 GPS_Rqst_Send_Position(gpsdevh *fd, double lat, double lon); #endif diff --git a/gpsbabel/jeeps/gpssend.c b/gpsbabel/jeeps/gpssend.c index b32ba2a27..d863683d9 100644 --- a/gpsbabel/jeeps/gpssend.c +++ b/gpsbabel/jeeps/gpssend.c @@ -4,6 +4,7 @@ ** @author Copyright (C) 1999 Alan Bleasby ** @version 1.0 ** @modified Dec 28 1999 Alan Bleasby. First version +** @modified Copyright (C) 2006 Robert Lipe ** @@ ** ** This library is free software; you can redistribute it and/or @@ -22,7 +23,7 @@ ** Boston, MA 02111-1307, USA. ********************************************************************/ #include "gps.h" -#include "gpsusbint.h" +#include "gpsserial.h" #include #include @@ -41,7 +42,7 @@ ** @return [void] ************************************************************************/ -void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n) +void GPS_Serial_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n) { UC *p; UC *q; @@ -53,11 +54,6 @@ void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n) p = data; q = (*packet)->data; - if (gps_is_usb) { - GPS_Make_Packet_usb(packet, type, data, n); - return; - } - (*packet)->dle = DLE; (*packet)->edle = DLE; (*packet)->etx = ETX; @@ -130,13 +126,11 @@ DiagS(void *buf, size_t sz) ** @return [int32] number of bytes in the packet ************************************************************************/ -int32 GPS_Write_Packet(int32 fd, GPS_PPacket packet) +int32 GPS_Serial_Write_Packet(gpsdevh *fd, GPS_PPacket packet) { size_t ret; const char *m1, *m2; - - if (gps_is_usb) - return GPS_Write_Packet_usb(fd, packet); + GPS_Diag("Tx Data:"); Diag(&packet->dle, 3); @@ -202,13 +196,10 @@ int32 GPS_Write_Packet(int32 fd, GPS_PPacket packet) ** @return [int32] success ************************************************************************/ -int32 GPS_Send_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec) +int32 GPS_Serial_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec) { UC data[2]; - if (gps_is_usb) - return 1; - GPS_Util_Put_Short(data,(US)(*rec)->type); GPS_Make_Packet(tra,LINK_ID[0].Pid_Ack_Byte,data,2); if(!GPS_Write_Packet(fd,*tra)) diff --git a/gpsbabel/jeeps/gpssend.h b/gpsbabel/jeeps/gpssend.h index f048fdec8..edd3f5b0d 100644 --- a/gpsbabel/jeeps/gpssend.h +++ b/gpsbabel/jeeps/gpssend.h @@ -11,12 +11,11 @@ extern "C" #define GPS_ARB_LEN 1024 -UC gps_sendbuf[GPS_ARB_LEN]; +void GPS_Serial_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n); +int32 GPS_Serial_Write_Packet(gpsdevh *fd, GPS_PPacket packet); +int32 GPS_Serial_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec); void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n); -int32 GPS_Write_Packet(int32 fd, GPS_PPacket packet); -int32 GPS_Send_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec); - #endif diff --git a/gpsbabel/jeeps/gpsserial.c b/gpsbabel/jeeps/gpsserial.c index 0da43cf2e..0496374a6 100644 --- a/gpsbabel/jeeps/gpsserial.c +++ b/gpsbabel/jeeps/gpsserial.c @@ -5,6 +5,7 @@ ** @version 1.0 ** @modified December 28th 1999 Alan Bleasby. First version ** @modified June 29th 2000 Alan Bleasby. NMEA additions +** @modified Copyright (C) 2006 Robert Lipe ** @@ ** ** This library is free software; you can redistribute it and/or @@ -23,7 +24,7 @@ ** Boston, MA 02111-1307, USA. ********************************************************************/ #include "gps.h" -#include "garminusb.h" +#include "gpsserial.h" #include #include #include @@ -56,18 +57,12 @@ char *rxdata[] = { #if defined (__WIN32__) || defined (__CYGWIN__) #include -/* - * Rather than teaching the rest of this code about Windows serial APIs - * we'll weenie out, violate good layering, and just keep our handle - * internal. This means we ignore that 'fd' number that gets passed in. - */ - -static HANDLE comport; +#include "gpsserial_win.h" /* * Display an error from the serial subsystem. */ -void GPS_Serial_Error(char *mb, ...) +void GPS_Serial_Error(const char *mb, ...) { va_list ap; char msg[200]; @@ -75,7 +70,6 @@ void GPS_Serial_Error(char *mb, ...) int b; va_start(ap, mb); -// strcpy(msg, msg); b = vsnprintf(msg, sizeof(msg), mb, ap); s = msg + b; *s++ = ':'; @@ -86,18 +80,13 @@ void GPS_Serial_Error(char *mb, ...) GPS_Error(msg); } -int32 GPS_Serial_On(const char *port, int32 *fd) +int32 GPS_Serial_On(const char *port, gpsdevh **dh) { DCB tio; COMMTIMEOUTS timeout; - - if (gps_is_usb) { - switch (gusb_open(port)) { - case 0: return 0; - case 1: return 1; - case 2: exit(0); - } - } + HANDLE comport; + win_serial_data *wsd = xcalloc(sizeof (win_serial_data), 1); + *dh = (gpsdevh*) wsd; comport = CreateFile(port, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); @@ -156,35 +145,31 @@ int32 GPS_Serial_On(const char *port, int32 *fd) gps_errno = SERIAL_ERROR; return 0; } - *fd = 1; + wsd->comport = comport; return 1; } -int32 GPS_Serial_Off(const char *port, int32 fd) +int32 GPS_Serial_Off(gpsdevh *dh) { - if (gps_is_usb) { - gusb_close(port); - } else { - CloseHandle(comport); - comport = INVALID_HANDLE_VALUE; - } + win_serial_data *wsd = (win_serial_data*)dh; + CloseHandle(wsd->comport); + wsd->comport = INVALID_HANDLE_VALUE; + xfree(wsd); return 1; } -int32 GPS_Serial_Chars_Ready(int32 fd) +int32 GPS_Serial_Chars_Ready(gpsdevh *dh) { COMSTAT lpStat; DWORD lpErrors; + win_serial_data *wsd = (win_serial_data*)dh; - ClearCommError(comport, &lpErrors, &lpStat); + ClearCommError(wsd->comport, &lpErrors, &lpStat); return (lpStat.cbInQue > 0); } -int32 GPS_Serial_Wait(int32 fd) +int32 GPS_Serial_Wait(gpsdevh *fd) { - - if (gps_is_usb) return 1; - /* Wait a short time before testing if data is ready. * The GPS II, in particular, has a noticable time responding * with a response to the device inquiry and if we give up on this @@ -196,13 +181,14 @@ int32 GPS_Serial_Wait(int32 fd) return GPS_Serial_Chars_Ready(fd); } -int32 GPS_Serial_Flush(int32 fd) +int32 GPS_Serial_Flush(gpsdevh *fd) { return 1; } -int32 GPS_Serial_Write(int32 ignored, const void *obuf, int size) +int32 GPS_Serial_Write(gpsdevh *dh, const void *obuf, int size) { + win_serial_data *wsd = (win_serial_data*)dh; DWORD len; /* @@ -215,34 +201,29 @@ int32 GPS_Serial_Write(int32 ignored, const void *obuf, int size) if (size == 0) { return 0; } - WriteFile (comport, obuf, size, &len, NULL); + WriteFile (wsd->comport, obuf, size, &len, NULL); if (len != (DWORD) size) { fatal ("Write error. Wrote %d of %d bytes.\n", len, size); } return len; } -int32 GPS_Serial_Read(int32 ignored, void *ibuf, int size) +int32 GPS_Serial_Read(gpsdevh * dh, void *ibuf, int size) { DWORD cnt = 0; + win_serial_data *wsd = (win_serial_data*)dh; - ReadFile(comport, ibuf, size, &cnt, NULL); + ReadFile(wsd->comport, ibuf, size, &cnt, NULL); return cnt; } -int32 GPS_Serial_Close(int32 fd, const char *port) -{ - return 1; -} - #else #include #include #include #include - -static struct termios gps_ttysave; +#include "gpsserial_posix.h" /* @func GPS_Serial_Restoretty *********************************************** ** @@ -253,32 +234,12 @@ static struct termios gps_ttysave; ** @return [int32] false upon error ************************************************************************/ -int32 GPS_Serial_Savetty(const char *port) +static int32 GPS_Serial_Savetty(int32 fd) { - int32 fd; - - if (gps_is_usb) return 1; - - if((fd = open(port, O_RDWR))==-1) - { - perror("open"); - gps_errno = SERIAL_ERROR; - GPS_Error("SERIAL: Cannot open serial port '%s'", port); - return 0; - } - if(tcgetattr(fd,&gps_ttysave)==-1) { - perror("tcgetattr"); gps_errno = HARDWARE_ERROR; - GPS_Error("SERIAL: tcgetattr error"); - return 0; - } - - if(!GPS_Serial_Close(fd,port)) - { - gps_errno = SERIAL_ERROR; - GPS_Error("GPS_Serial_Savetty: Close error"); + GPS_Serial_Error("SERIAL: tcgetattr error"); return 0; } @@ -295,32 +256,19 @@ int32 GPS_Serial_Savetty(const char *port) ** @return [int32] false upon error ************************************************************************/ -int32 GPS_Serial_Restoretty(const char *port) +static int32 GPS_Serial_Restoretty(int fd) { - int32 fd; - - if (gps_is_usb) return 1; - - if((fd = open(port, O_RDWR))==-1) - { - perror("open"); - gps_errno = HARDWARE_ERROR; - GPS_Error("SERIAL: Cannot open serial port '%s'", port); - return 0; - } - if(tcsetattr(fd, TCSAFLUSH, &gps_ttysave)==-1) { - perror("ioctl"); gps_errno = HARDWARE_ERROR; - GPS_Error("SERIAL: tcsetattr error"); + GPS_Serial_Error("SERIAL: tcsetattr error"); return 0; } return 1; } - +#endif /* @func GPS_Serial_Open *********************************************** ** @@ -332,9 +280,10 @@ int32 GPS_Serial_Restoretty(const char *port) ** @return [int32] false upon error ************************************************************************/ -int32 GPS_Serial_Open(int32 *fd, const char *port) +int32 GPS_Serial_Open(gpsdevh *dh, const char *port) { struct termios tty; + posix_serial_data *psd = (posix_serial_data *)dh; /* * This originally had O_NDELAY | O_NOCTTY in here, but this @@ -342,21 +291,20 @@ int32 GPS_Serial_Open(int32 *fd, const char *port) * and the rest of the code doesn't _REALLY_ handle the partial * write/retry case anyway. - robertl */ - if((*fd = open(port, O_RDWR))==-1) + if((psd->fd = open(port, O_RDWR))==-1) { - perror("open"); - GPS_Error("SERIAL: Cannot open serial port '%s'", port); + GPS_Serial_Error("XSERIAL: Cannot open serial port '%s'", port); gps_errno = SERIAL_ERROR; return 0; } - if(tcgetattr(*fd,&tty)==-1) + if(tcgetattr(psd->fd,&psd->gps_ttysave)==-1) { - perror("tcgetattr"); - GPS_Error("SERIAL: tcgetattr error"); - gps_errno = SERIAL_ERROR; + gps_errno = HARDWARE_ERROR; + GPS_Serial_Error("SERIAL: tcgetattr error"); return 0; } + tty = psd->gps_ttysave; tty.c_cflag &= ~(CSIZE); tty.c_cflag |= (CREAD | CS8 | CLOCAL); @@ -369,18 +317,40 @@ int32 GPS_Serial_Open(int32 *fd, const char *port) tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 0; - if(tcsetattr(*fd,TCSANOW,&tty)==-1) + if(tcsetattr(psd->fd,TCSANOW,&tty)==-1) { - perror("tcsetattr"); - GPS_Error("SERIAL: tcsetattr error"); + GPS_Serial_Error("SERIAL: tcsetattr error"); return 0; } return 1; } -int32 GPS_Serial_Read(int32 handle, void *ibuf, int size) +/* + * Display an error from the serial subsystem. + */ +void GPS_Serial_Error(const char *mb, ...) +{ + va_list ap; + char msg[200]; + char *s; + int b; + + va_start(ap, mb); + b = vsnprintf(msg, sizeof(msg), mb, ap); + s = msg + b; + *s++ = ':'; + *s++ = ' '; + +// FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, +// GetLastError(), 0, s, sizeof(msg) - b - 2, 0 ); + strcat(msg, strerror(errno)); + GPS_Error(msg); +} + +int32 GPS_Serial_Read(gpsdevh *dh, void *ibuf, int size) { + posix_serial_data *psd = (posix_serial_data *)dh; #if GARMULATOR static int l; static char *rp; @@ -402,13 +372,14 @@ int32 GPS_Serial_Read(int32 handle, void *ibuf, int size) return 1; #else - return read(handle, ibuf, size); + return read(psd->fd, ibuf, size); #endif } -int32 GPS_Serial_Write(int32 handle, const void *obuf, int size) +int32 GPS_Serial_Write(gpsdevh *dh, const void *obuf, int size) { - return write(handle, obuf, size); + posix_serial_data *psd = (posix_serial_data *)dh; + return write(psd->fd, obuf, size); } @@ -420,14 +391,13 @@ int32 GPS_Serial_Write(int32 handle, const void *obuf, int size) ** ** @return [int32] false upon error ************************************************************************/ -int32 GPS_Serial_Flush(int32 fd) +int32 GPS_Serial_Flush(gpsdevh *fd) { - if (gps_is_usb) return 1; - - if(tcflush(fd,TCIOFLUSH)) + posix_serial_data *psd = (posix_serial_data *)fd; + + if(tcflush(psd->fd,TCIOFLUSH)) { - perror("tcflush"); - GPS_Error("SERIAL: tcflush error"); + GPS_Serial_Error("SERIAL: tcflush error"); gps_errno = SERIAL_ERROR; return 0; } @@ -447,14 +417,20 @@ int32 GPS_Serial_Flush(int32 fd) ** @return [int32] false upon error ************************************************************************/ -int32 GPS_Serial_Close(int32 fd, const char *port) +int32 GPS_Serial_Close(gpsdevh *fd) { - if (gps_is_usb) return 1; + posix_serial_data *psd = (posix_serial_data *)fd; - if(close(fd)==-1) + if(tcsetattr(psd->fd, TCSAFLUSH, &psd->gps_ttysave)==-1) { - perror("close"); - GPS_Error("SERIAL: Error closing serial port"); + gps_errno = HARDWARE_ERROR; + GPS_Serial_Error("SERIAL: tcsetattr error"); + return 0; + } + + if(close(psd->fd)==-1) + { + GPS_Serial_Error("SERIAL: Error closing serial port"); gps_errno = SERIAL_ERROR; return 0; } @@ -472,10 +448,13 @@ int32 GPS_Serial_Close(int32 fd, const char *port) ** @return [int32] true if chars waiting ************************************************************************/ -int32 GPS_Serial_Chars_Ready(int32 fd) +int32 GPS_Serial_Chars_Ready(gpsdevh *dh) { fd_set rec; struct timeval t; + posix_serial_data *psd = (posix_serial_data *)dh; + int32 fd = psd->fd; + #if GARMULATOR static foo; /* Return sporadic reads just to torment the rest of the code. */ @@ -510,21 +489,20 @@ int32 GPS_Serial_Chars_Ready(int32 fd) ** @return [int32] true if serial chars waiting ************************************************************************/ -int32 GPS_Serial_Wait(int32 fd) +int32 GPS_Serial_Wait(gpsdevh *dh) { fd_set rec; struct timeval t; - - if (gps_is_usb) return 1; + posix_serial_data *psd = (posix_serial_data *)dh; FD_ZERO(&rec); - FD_SET(fd,&rec); + FD_SET(psd->fd,&rec); t.tv_sec = 0; - t.tv_usec = usecDELAY; + t.tv_usec = 180000; /* Microseconds before GPS sends A001 */ - (void) select(fd+1,&rec,NULL,NULL,&t); - if(FD_ISSET(fd,&rec)) + (void) select(psd->fd+1,&rec,NULL,NULL,&t); + if(FD_ISSET(psd->fd,&rec)) return 1; return 0; @@ -542,19 +520,12 @@ int32 GPS_Serial_Wait(int32 fd) ** @return [int32] success ************************************************************************/ -int32 GPS_Serial_On(const char *port, int32 *fd) +int32 GPS_Serial_On(const char *port, gpsdevh **dh) { - if (gps_is_usb) { - return gusb_init(port); - } - if(!GPS_Serial_Savetty(port)) - { - GPS_Error("Cannot access serial port '%s'", port); - gps_errno = SERIAL_ERROR; - return 0; - } + posix_serial_data *psd = xcalloc(sizeof (posix_serial_data), 1); + *dh = (gpsdevh*) psd; - if(!GPS_Serial_Open(fd,port)) + if(!GPS_Serial_Open((gpsdevh *) psd,port)) { GPS_Error("Cannot open serial port '%s'", port); gps_errno = SERIAL_ERROR; @@ -576,22 +547,17 @@ int32 GPS_Serial_On(const char *port, int32 *fd) ** @return [int32] success ************************************************************************/ -int32 GPS_Serial_Off(const char *port, int32 fd) +int32 GPS_Serial_Off(gpsdevh *dh) { - if(!GPS_Serial_Close(fd,port)) + + if(!GPS_Serial_Close(dh)) { GPS_Error("Error Closing port"); gps_errno = HARDWARE_ERROR; return 0; } + dh = NULL; - if(!GPS_Serial_Restoretty(port)) - { - GPS_Error("Error restoring port"); - gps_errno = HARDWARE_ERROR; - return 0; - } - return 1; } diff --git a/gpsbabel/jeeps/gpsserial.h b/gpsbabel/jeeps/gpsserial.h index 7726bfbbc..bf245105e 100644 --- a/gpsbabel/jeeps/gpsserial.h +++ b/gpsbabel/jeeps/gpsserial.h @@ -11,20 +11,22 @@ extern "C" #define usecDELAY 180000 /* Microseconds before GPS sends A001 */ -int32 GPS_Serial_Chars_Ready(int32 fd); -int32 GPS_Serial_Close(int32 fd, const char *port); -int32 GPS_Serial_Open(int32 *fd, const char *port); -int32 GPS_Serial_Open_NMEA(int32 *fd, const char *port); -int32 GPS_Serial_Restoretty(const char *port); -int32 GPS_Serial_Savetty(const char *port); -int32 GPS_Serial_On(const char *port, int32 *fd); -int32 GPS_Serial_Off(const char *port, int32 fd); -int32 GPS_Serial_Wait(int32 fd); -int32 GPS_Serial_Flush(int32 fd); -int32 GPS_Serial_On_NMEA(const char *port, int32 *fd); -int32 GPS_Serial_Read(int32 ignored, void *ibuf, int size); -int32 GPS_Serial_Write(int32 ignored, const void *obuf, int size); -void GPS_Serial_Error(char *hdr, ...); +int32 GPS_Serial_Chars_Ready(gpsdevh * fd); +// int32 GPS_Serial_Close(int32 fd, const char *port); +// int32 GPS_Serial_Open(int32 *fd, const char *port); +// int32 GPS_Serial_Open_NMEA(int32 *fd, const char *port); +// int32 GPS_Serial_Restoretty(const char *port); +// int32 GPS_Serial_Savetty(const char *port); +int32 GPS_Serial_On(const char *port, gpsdevh **fd); +int32 GPS_Serial_Off(gpsdevh *fd); +int32 GPS_Serial_Wait(gpsdevh *fd); +int32 GPS_Serial_Flush(gpsdevh *fd); +// int32 GPS_Serial_On_NMEA(const char *port, gpsdevh **fd); +int32 GPS_Serial_Read(gpsdevh *fd, void *ibuf, int size); +int32 GPS_Serial_Write(gpsdevh *fd, const void *obuf, int size); +int32 GPS_Serial_Write_Packet(gpsdevh *fd, GPS_PPacket packet); +int32 GPS_Serial_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec); +void GPS_Serial_Error(const char *hdr, ...); #endif diff --git a/gpsbabel/jeeps/gpsusbcommon.c b/gpsbabel/jeeps/gpsusbcommon.c index 38dfbfb62..94e6adac0 100644 --- a/gpsbabel/jeeps/gpsusbcommon.c +++ b/gpsbabel/jeeps/gpsusbcommon.c @@ -20,10 +20,9 @@ */ -#include #include "gps.h" #include "garminusb.h" - +#include "gpsusbcommon.h" /* * This receive logic is a little convoluted as we go to some efforts here @@ -36,17 +35,47 @@ enum { rs_frombulk } receive_state; +static gusb_llops_t *gusb_llops; + +/* Decide when to truncate packets for debug output */ +#define DEBUG_THRESH ((global_opts.debug_level < 5) && (i > 10)) + +/* Called from OS layer to register its low-level entry points. */ +void +gusb_register_ll(gusb_llops_t *p) +{ + gusb_llops = p; +} + int -gusb_close(const char *portname) +gusb_close(gpsdevh *dh) { garmin_usb_packet scratch; + + memset(&scratch, 0, sizeof(scratch)); + switch (receive_state) { case rs_frombulk: gusb_cmd_get(&scratch, sizeof(scratch)); break; + default: + break; + } + + gusb_llops->llop_close(dh); + return 1; + +#if BOOGER + garmin_usb_packet scratch = {0}; +abort(); + switch (receive_state) { + case rs_frombulk: + gusb_cmd_get(dh, &scratch, sizeof(scratch)); + break; } return 1; +#endif } @@ -55,18 +84,18 @@ gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz) { int rv; unsigned char *buf = (unsigned char *) &ibuf->dbuf; - + int orig_receive_state; top: + orig_receive_state = receive_state; switch (receive_state) { case rs_fromintr: - rv = gusb_cmd_get_os(ibuf, sz); - break; + rv = gusb_llops->llop_get_intr(ibuf, sz); + break; case rs_frombulk: - rv = gusb_cmd_get_os_bulk(ibuf, sz); - if (rv == 0) { - receive_state = rs_fromintr; - } - break; + rv = gusb_llops->llop_get_bulk(ibuf, sz); + break; + default: + fatal("Unknown receiver state %d\n", receive_state); } if (gps_show_bytes) { @@ -76,21 +105,44 @@ top: GPS_Diag("RX (%s) [%d]:", receive_state == rs_fromintr ? "intr" : "bulk", rv); - for(i=0;igusb_pkt.pkt_id[0], ibuf->gusb_pkt.databuf[0], &m2); +if ((rv == 0) && (receive_state == rs_frombulk) ) {m1= "RET2INTR";m2=NULL;}; GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); } - if (ibuf->gusb_pkt.pkt_id[0] == GUSB_REQUEST_BULK) { + /* Adjust internal state and retry the read */ + if ((rv > 0) && (ibuf->gusb_pkt.pkt_id[0] == GUSB_REQUEST_BULK)) { receive_state = rs_frombulk; goto top; } + /* + * If we were reading from the bulk pipe and we just got + * a zero request, adjust our internal state. + * It's tempting to retry the read here to hide this "stray" + * packet from our callers, but that only works when you know + * there's another packet coming. That works in every case + * except the A000 discovery sequence. + */ + if ((receive_state == rs_frombulk) && (rv <= 0)) { + receive_state = rs_fromintr; + } return rv; } @@ -98,12 +150,12 @@ top: int gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz) { - int rv, i; + unsigned int rv, i; unsigned char *obuf = (unsigned char *) &opkt->dbuf; const char *m1, *m2; - rv = gusb_cmd_send_os(opkt, sz); + rv = gusb_llops->llop_send(opkt, sz); if (gps_show_bytes) { GPS_Diag("TX [%d]:", sz); @@ -129,36 +181,43 @@ gusb_list_units() for (i = 0; i < GUSB_MAX_UNITS; i++) { if (garmin_unit_info[i].serial_number) { - printf("%d %u %s\n", i, + printf("%d %lu %lu %s\n", i, garmin_unit_info[i].serial_number, + garmin_unit_info[i].unit_id, garmin_unit_info[i].product_identifier ); } } } -char * -gusb_id_unit(void) +void +gusb_id_unit(struct garmin_unit_info *gu) { static const char oid[12] = {20, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, 0, 0}; garmin_usb_packet iresp; int i; - char *rv = NULL; gusb_cmd_send((garmin_usb_packet *)oid, sizeof(oid)); for (i = 0; i < 25; i++) { iresp.gusb_pkt.type = 0; if (gusb_cmd_get(&iresp, sizeof(iresp)) < 0) { - return rv; + return; } if (le_read16(iresp.gusb_pkt.pkt_id) == 0xff) { - rv = strdup((char *) iresp.gusb_pkt.databuf+4); + gu->product_identifier = xstrdup((char *) iresp.gusb_pkt.databuf+4); + gu->unit_id = le_read16(iresp.gusb_pkt.databuf+0); + gu->unit_version = le_read16(iresp.gusb_pkt.databuf+2); } + /* + * My goodnesss, this is fragile. During command syncup, + * we need to know if we're at the end. The 0xfd packet + * is promised by Garmin engineering to be the last. + */ + if (le_read16(iresp.gusb_pkt.pkt_id) == 0xfd) return; } -fatal("eek!"); - + fatal("Unable to sync with Garmin USB device in %d attempts.", i); } void @@ -170,6 +229,11 @@ gusb_syncup(void) garmin_usb_packet iresp; int i; + /* + * This is our first communication with the unit. + */ + receive_state = rs_fromintr; + for(i = 0; i < 25; i++) { le_write16(&iresp.gusb_pkt.pkt_id, 0); le_write32(&iresp.gusb_pkt.datasz, 0); @@ -182,7 +246,7 @@ gusb_syncup(void) (le_read32(iresp.gusb_pkt.datasz) == 4)) { unsigned serial_number = le_read32(iresp.gusb_pkt.databuf); garmin_unit_info[unit_number].serial_number = serial_number; - garmin_unit_info[unit_number].product_identifier = gusb_id_unit(); + gusb_id_unit(&garmin_unit_info[unit_number]); unit_number++; diff --git a/gpsbabel/jeeps/gpsusbint.h b/gpsbabel/jeeps/gpsusbint.h index 3a0e00137..8d91da24a 100644 --- a/gpsbabel/jeeps/gpsusbint.h +++ b/gpsbabel/jeeps/gpsusbint.h @@ -3,7 +3,7 @@ These symbols should not be publicly used. They're "friend" functions of USB details internal to jeeps. - Copyright (C) 2005 Robert Lipe, robertlipe@usa.net + Copyright (C) 2005, 2006 Robert Lipe, robertlipe@usa.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ */ -int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet); +int32 GPS_Packet_Read_usb(gpsdevh *fd, GPS_PPacket *packet, int eatbulk); void GPS_Make_Packet_usb(GPS_PPacket *packet, UC type, UC *data, int16 n); -int32 GPS_Write_Packet_usb(int32 fd, GPS_PPacket packet); +int32 GPS_Write_Packet_usb(gpsdevh *fd, GPS_PPacket packet); diff --git a/gpsbabel/jeeps/gpsusbread.c b/gpsbabel/jeeps/gpsusbread.c index 14a12ccfc..1cdce1df2 100644 --- a/gpsbabel/jeeps/gpsusbread.c +++ b/gpsbabel/jeeps/gpsusbread.c @@ -1,7 +1,7 @@ /* Decompose an incoming USB packet to make it look like a serial one. - Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + Copyright (C) 2004, 2006, 2006 Robert Lipe, robertlipe@usa.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,36 +23,40 @@ #include "garminusb.h" #include "gpsusbint.h" -int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet) +/* + * Return values are: + * Negative on error. + * 1 if read success - even if empty packet. + */ +int32 GPS_Packet_Read_usb(gpsdevh *dh, GPS_PPacket *packet, int eat_bulk) { int32 n; - int32 i; int32 payload_size; - const char *m1; - const char *m2; garmin_usb_packet pkt; + memset(&pkt, 0, sizeof(pkt)); +do_over: n = gusb_cmd_get(&pkt, sizeof(pkt)); - if ( n <= 0 ) { -// FIXME: revisit why we're intermittend getting read errors here... -// fprintf(stderr, "Eeek %d\n", n); - (*packet)->n = (UC) 0; + if ( n < 0 ) { +fprintf(stderr, "Eeek %d\n", n); return n; } - if (1 && gps_show_bytes) { - GPS_Diag("\nRx Data:[%d]",n); - for (i = 0; i < n; i++) - GPS_Diag("%02x ", pkt.dbuf[i]); - for (i = 0; i < n; i++) - GPS_Diag("%c", isalnum(pkt.dbuf[i]) ? pkt.dbuf[i] : '.'); - m1 = Get_Pkt_Type(pkt.gusb_pkt.pkt_id[0], pkt.gusb_pkt.databuf[0], &m2); - GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); - + /* + * This is a horrible hack for 276/296. This family sometimes + * switches between bulk and interrupt on EVERY packet. Rather + * than bother all the callers with that bit of unpleasantness, + * silently consume zero byte "switch back to intr" packets here. + * + * The one caller that doesn't want this hidden is device discovery + * in the A000 handler. + */ + if ((n == 0) && eat_bulk) { + goto do_over; } - + /* * Populate members of serial packet from USB packet. The * copy here seems wasteful, but teaching all the callers about @@ -64,5 +68,6 @@ int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet) payload_size = le_read32(&pkt.gusb_pkt.datasz); (*packet)->n = (UC) payload_size; memcpy((*packet)->data, &pkt.gusb_pkt.databuf, payload_size); - return payload_size; + + return 1; } diff --git a/gpsbabel/jeeps/gpsusbsend.c b/gpsbabel/jeeps/gpsusbsend.c index 798b5af3d..bd376b7e0 100644 --- a/gpsbabel/jeeps/gpsusbsend.c +++ b/gpsbabel/jeeps/gpsusbsend.c @@ -1,7 +1,7 @@ /* Form GarminUSB packets to send. - Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + Copyright (C) 2004, 2005, 2006 Robert Lipe, robertlipe@usa.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -43,7 +43,7 @@ GPS_Make_Packet_usb(GPS_PPacket *packet, UC type, UC *data, int16 n) } int32 -GPS_Write_Packet_usb(int32 fd, GPS_PPacket packet) +GPS_Write_Packet_usb(gpsdevh *dh, GPS_PPacket packet) { garmin_usb_packet gp; memset(&gp, 0, sizeof(gp)); diff --git a/gpsbabel/jeeps/gpsusbstub.c b/gpsbabel/jeeps/gpsusbstub.c index 2209783f5..d5ee15be8 100644 --- a/gpsbabel/jeeps/gpsusbstub.c +++ b/gpsbabel/jeeps/gpsusbstub.c @@ -1,7 +1,7 @@ /* Stubs to keep build happy when USB just isn't available to us. - Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + Copyright (C) 2004, 2006 Robert Lipe, robertlipe@usa.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,9 +20,9 @@ */ -#include "garminusb.h" #include "config.h" -#if !HAVE_LIBUSB +#if !HAVE_LIBUSB +#include "garminusb.h" const char no_usb[] = "USB suport is not available in this build.\n"; int diff --git a/gpsbabel/jeeps/gpsusbwin.c b/gpsbabel/jeeps/gpsusbwin.c index a503c9cf2..cd217cb67 100644 --- a/gpsbabel/jeeps/gpsusbwin.c +++ b/gpsbabel/jeeps/gpsusbwin.c @@ -2,7 +2,7 @@ /* Windows layer of Garmin/USB protocol. - Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + Copyright (C) 2004, 2006, 2006 Robert Lipe, robertlipe@usa.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,6 +31,8 @@ #include "gps.h" #include "gpsapp.h" #include "garminusb.h" +#include "gpsusbcommon.h" +#include "gpsusbwin.h" /* Constants from Garmin doc. */ @@ -49,140 +51,25 @@ DEFINE_GUID(GARMIN_GUID, 0x2c9c45c2L, 0x8e7d, 0x4c08, 0xa1, 0x2d, 0x81, 0x6b, 0x (FILE_DEVICE_UNKNOWN, 0x851, METHOD_BUFFERED, FILE_ANY_ACCESS) -static HANDLE *usb_handle ; +static HANDLE *usb_handle = INVALID_HANDLE_VALUE; static int usb_tx_packet_size ; -static const char oinit[12] = {0, 0, 0, 0, 0x05, 0, 0, 0, 0, 0, 0, 0}; -garmin_usb_packet iresp; -garmin_usb_packet iresp_junk; -static int ct; - -static char * id_unit(void); - -int -gusb_open(const char *pname) -{ - int maxtries; - int maxct = 10; - int unit_number = 0; - int req_unit_number = 0; - - SP_INTERFACE_DEVICE_DATA devinterface; - PSP_INTERFACE_DEVICE_DETAIL_DATA pdd = NULL; - SP_DEVINFO_DATA devinfo; - HDEVINFO hdevinfo; - DWORD size; - if (ct++) return 1; - - if (strlen(pname) > 4) { - req_unit_number = atoi(pname+4); - GPS_Diag("Searching for USB unit number %d\n", unit_number); -// if (req_unit_number == -2) { -// printf("%d %u %s\n", 0, 3019840053, "GPSMap60CS Software Version 3.50"); -// exit(0); -// } - } - - hdevinfo = SetupDiGetClassDevs( (GUID *) &GARMIN_GUID, NULL, NULL, - DIGCF_PRESENT|DIGCF_INTERFACEDEVICE); - - if (hdevinfo == INVALID_HANDLE_VALUE) { - GPS_Serial_Error("SetupDiGetClassDevs failed"); - warning("Is the Garmin USB driver installed?"); - return 0; - } - - /* Get the device associated with this index. */ - devinterface.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA); - if (!SetupDiEnumDeviceInterfaces(hdevinfo, NULL, (GUID *) &GARMIN_GUID, - 0, &devinterface)) { - GPS_Serial_Error("SetupDiEnumDeviceInterfaces"); - warning("Is the Garmin USB unit powered up and connected?"); - return 0; - } - - SetupDiGetDeviceInterfaceDetail(hdevinfo, &devinterface, - NULL, 0, &size, NULL); - - pdd = malloc(size); - pdd->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); - devinfo.cbSize = sizeof(SP_DEVINFO_DATA); - - if (!SetupDiGetDeviceInterfaceDetail(hdevinfo, &devinterface, pdd, size, NULL, &devinfo)) { - GPS_Serial_Error("SetupDiGetDeviceInterfaceDetail"); - return 0; - } - - /* Whew. All that just to get something we can open... */ - GPS_Diag("Windows GUID for interface %d is \n\t%s\n", unit_number, - pdd->DevicePath); - usb_handle = CreateFile(pdd->DevicePath, GENERIC_READ|GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL ); - if (usb_handle == INVALID_HANDLE_VALUE) { - GPS_Serial_Error("CreateFile on '%' failed", pdd->DevicePath); - return 0; - } - - if(!DeviceIoControl(usb_handle, IOCTL_GARMIN_USB_BULK_OUT_PACKET_SIZE, NULL, 0, - &usb_tx_packet_size, GARMIN_USB_INTERRUPT_DATA_SIZE, &size, NULL)) { - fatal("Couldn't get USB packet size.\n"); - } - - if (pdd) { - free(pdd); - } - SetupDiDestroyDeviceInfoList(hdevinfo); - - for (maxtries = maxct; maxtries; maxtries--) { - - le_write16(&iresp.gusb_pkt.pkt_id, 0); - le_write32(&iresp.gusb_pkt.datasz, 0); - le_write32(&iresp.gusb_pkt.databuf, 0); - - gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit)); - gusb_cmd_get(&iresp, sizeof(iresp)); - - if ((le_read16(iresp.gusb_pkt.pkt_id) == 6) && - (le_read32(iresp.gusb_pkt.datasz) == 4)) { - unsigned serial_number = le_read32(iresp.gusb_pkt.databuf); - GPS_Diag("Serial %u. Synced in %d\n", - serial_number, - maxct - maxtries); - garmin_unit_info[unit_number].serial_number = serial_number; - garmin_unit_info[unit_number].os_identifier = strdup(pdd->DevicePath); - garmin_unit_info[unit_number].product_identifier = id_unit(); - if (req_unit_number < 0) { - printf("%d %u %s\n", unit_number, serial_number, garmin_unit_info[unit_number].product_identifier); - return 2; - } - return 1; - } - } - fatal("Unable to establish USB syncup within %d tries.\n", maxct); - return 0; -} - int -gusb_close(const char *portname) +gusb_win_close(const char *portname) { if (usb_handle != INVALID_HANDLE_VALUE) { -#if 0 - /* FIXME: we should probably release things and delete the "ct" - * reference count above... - */ CloseHandle(usb_handle); usb_handle = INVALID_HANDLE_VALUE; -#endif } - return 0; + + return 0; } -int -gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz) +static int +gusb_win_get(garmin_usb_packet *ibuf, size_t sz) { DWORD rxed = GARMIN_USB_INTERRUPT_DATA_SIZE; unsigned char *buf = (unsigned char *) &ibuf->dbuf; - int i; int tsz=0; unsigned char *obuf = buf; @@ -202,44 +89,32 @@ gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz) break; } } - - if (gps_show_bytes) { - const char *m1, *m2; - printf("RX [%d]:", tsz); - for(i=0;igusb_pkt.pkt_id[0], ibuf->gusb_pkt.databuf[0], &m2); - GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); - printf("\n"); - } return tsz; } -int -gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz) +static int +gusb_win_get_bulk(garmin_usb_packet *ibuf, size_t sz) +{ + int n; + DWORD rsz; + unsigned char *buf = (unsigned char *) &ibuf->dbuf; + + n = ReadFile(usb_handle, buf, sz, &rsz, NULL); + + return rsz; +} + +static int +gusb_win_send(const garmin_usb_packet *opkt, size_t sz) { DWORD rsz; - size_t i; unsigned char *obuf = (unsigned char *) &opkt->dbuf; - const char *m1, *m2; /* The spec warns us about making writes an exact multiple * of the packet size, but isn't clear whether we can issue * data in a single call to WriteFile if it spans buffers. */ WriteFile(usb_handle, obuf, sz, &rsz, NULL); - if (gps_show_bytes) { - printf("TX [%d]:", rsz); - for(i=0;igusb_pkt.pkt_id[0], opkt->gusb_pkt.databuf[0], &m2); - GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : ""); - } if (rsz != sz) { fatal ("Error sending %d bytes. Successfully sent %d\n", sz, rsz); @@ -254,47 +129,127 @@ gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz) return rsz; } -static char * -id_unit(void) +static gusb_llops_t win_llops = { + gusb_win_get, + gusb_win_get_bulk, + gusb_win_send, + gusb_win_close +}; + +static +HANDLE * garmin_usb_start(HDEVINFO* hdevinfo, SP_DEVICE_INTERFACE_DATA *infodata) { -static const unsigned char oid[12] = {20, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, 0, 0}; - /* - * Identify the unit before getting into all the protocol gunk. - * We get two packets back, but we discard the protocol array - * for now. - */ + DWORD size; + PSP_INTERFACE_DEVICE_DETAIL_DATA pdd = NULL; + SP_DEVINFO_DATA devinfo; + + SetupDiGetDeviceInterfaceDetail(hdevinfo, infodata, + NULL, 0, &size, NULL); + + pdd = xmalloc(size); + pdd->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); + + devinfo.cbSize = sizeof(SP_DEVINFO_DATA); + if (!SetupDiGetDeviceInterfaceDetail(hdevinfo, infodata, + pdd, size, NULL, &devinfo)) { + GPS_Serial_Error("SetupDiGetDeviceInterfaceDetail"); + return NULL; + } - gusb_cmd_send((garmin_usb_packet *)oid, sizeof(oid)); - gusb_cmd_get(&iresp, sizeof(iresp)); - gusb_cmd_get(&iresp_junk, sizeof(iresp_junk)); + /* Whew. All that just to get something we can open... */ + GPS_Diag("Windows GUID for interface is \n\t%s\n", + pdd->DevicePath); - if (iresp.gusb_pkt.type == 20 && - le_read16(iresp.gusb_pkt.pkt_id) == 0xff) { - return strdup(iresp.gusb_pkt.databuf+4); + if (usb_handle != INVALID_HANDLE_VALUE) { + fatal("garmin_usb_start called while device already started.\n"); } - return NULL; -} + usb_handle = CreateFile(pdd->DevicePath, GENERIC_READ|GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL ); + if (usb_handle == INVALID_HANDLE_VALUE) { + GPS_Serial_Error("CreateFile on '%' failed", pdd->DevicePath); + return NULL; + } + + if(!DeviceIoControl(usb_handle, IOCTL_GARMIN_USB_BULK_OUT_PACKET_SIZE, + NULL, 0, &usb_tx_packet_size, GARMIN_USB_INTERRUPT_DATA_SIZE, + &size, NULL)) { + fatal("Couldn't get USB packet size.\n"); + } + + gusb_syncup(); + return usb_handle; +} -#if 0 -main() +/* + * Main entry point from the upper layer. Walk the device tree, find our + * device, and light it up. + */ +int +gusb_init(const char *pname, gpsdevh **dh) { - DWORD sz; -char ocmd[] = {00, 00, 00, 00, 05, 00, 00, 00, 00, 00, 00, 00}; -char ocmd2[] = {0x14, 00, 00, 00, 0xfe, 00, 00, 00, 00, 00, 00, 00}; - gusb_open(); - WriteFile(usb_handle, ocmd, sizeof(ocmd), &sz, NULL); - printf("Wrote %d\n", sz); - usb_intr_get(); - - WriteFile(usb_handle, ocmd2, sizeof(ocmd2), &sz, NULL); - printf("Wrote %d\n", sz); - usb_intr_get(); - - WriteFile(usb_handle, ocmd2, sizeof(ocmd2), &sz, NULL); - printf("Wrote %d\n", sz); - usb_intr_get(); + int req_unit_number = 0; + int un = 0; + int match; + + HDEVINFO hdevinfo; + SP_DEVICE_INTERFACE_DATA devinterface; + + winusb_unit_data *wud = xcalloc(sizeof (winusb_unit_data), 1); + *dh = (gpsdevh*) wud; + + gusb_register_ll(&win_llops); + + if (strlen(pname) > 4) { + req_unit_number = atoi(pname+4); + } + + hdevinfo = SetupDiGetClassDevs( (GUID *) &GARMIN_GUID, NULL, NULL, + DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); + + if (hdevinfo == INVALID_HANDLE_VALUE) { + GPS_Serial_Error("SetupDiGetClassDevs failed"); + warning("Is the Garmin USB driver installed?"); + return 0; + } + + devinterface.cbSize = sizeof(devinterface); + + if (req_unit_number >= 0) { + if (!SetupDiEnumDeviceInterfaces(hdevinfo, NULL, + (GUID *) &GARMIN_GUID, + req_unit_number, &devinterface)) { + GPS_Serial_Error("SetupDiEnumDeviceInterfaces"); + warning("Is the Garmin USB unit number %d powered up and connected?", un); + return 0; + } + /* We've matched. Now start the specific unit. */ + garmin_usb_start(hdevinfo, &devinterface); + return 1; + } + + /* + * Out unit nunber is less than zero, so loop over all units + * and display them. + */ + for(match = 0;;match++) { + if (!SetupDiEnumDeviceInterfaces(hdevinfo, NULL, + (GUID *) &GARMIN_GUID, match, &devinterface)) { + if (GetLastError() == ERROR_NO_MORE_ITEMS) { + break; + } else { + GPS_Serial_Error("SetupDiEnumDeviceInterfaces"); + warning("Is the Garmin USB unit number %d powered up and connected?", un); + return 0; + } + } + /* We've matched. Now start the specific unit. */ + garmin_usb_start(hdevinfo, &devinterface); + gusb_close("blah"); + } + gusb_list_units(); + exit (0); } -#endif + #endif /* !defined(NO_USB) */ diff --git a/gpsbabel/jeeps/gpsutil.h b/gpsbabel/jeeps/gpsutil.h index e22a8ba60..faf1e0f06 100644 --- a/gpsbabel/jeeps/gpsutil.h +++ b/gpsbabel/jeeps/gpsutil.h @@ -26,6 +26,7 @@ uint32 GPS_Util_Get_Uint(const UC *s); void GPS_Warning(char *s); void GPS_Error(char *fmt, ...); +void GPS_Serial_Error(const char *hdr, ...); void GPS_Fatal(char *s); void GPS_Enable_Error(void); void GPS_Enable_Warning(void); -- 2.30.2